2.3. Widget Classing   

The widget_class field of a widget points to its widget class structure, which contains information that is constant across all widgets of that class. As a consequence, widgets usually do not implement directly callable procedures; rather, they implement procedures, called methods, that are available through their widget class structure. These methods are invoked by generic procedures that envelop common actions around the methods implemented by the widget class. Such procedures are applicable to all widgets of that class and also to widgets whose classes are subclasses of that class.

All widget classes are a subclass of Core and can be subclassed further. Subclassing reduces the amount of code and declarations necessary to make a new widget class that is similar to an existing class. For example, you do not have to describe every resource your widget uses in an XtResourceList. Instead, you describe only the resources your widget has that its superclass does not. Subclasses usually inherit many of their superclasses' procedures (for example, the expose procedure or geometry handler).

Subclassing, however, can be taken too far. If you create a subclass that inherits none of the procedures of its superclass, you should consider whether you have chosen the most appropriate superclass.

To make good use of subclassing, widget declarations and naming conventions are highly stylized. A widget consists of three files:

A public .h file, used by client widgets or applications.

A private .h file, used by widgets whose classes are subclasses of the widget class.

A .c file, which implements the widget.

2.3.1. Widget Naming Conventions   

The Intrinsics provide a vehicle by which programmers can create new widgets and organize a collection of widgets into an application. To ensure that applications need not deal with as many styles of capitalization and spelling as the number of widget classes it uses, the following guidelines should be followed when writing new widgets:

Use the X library naming conventions that are applicable. For example, a record component name is all lower case and uses underscores (_) for compound words (for example, background_pixmap). Type and procedure names start with upper case and use capitalization for compound words (for example, ArgList or XtSetValues).

A resource name is spelled identically to the field name except that compound names use capitalization rather than underscore. To let the compiler catch spelling errors, each resource name should have a symbolic identifier prefixed with ``XtN''. For example, the background_pixmap field has the corresponding identifier XtNbackgroundPixmap, which is defined as the string ``backgroundPixmap''. Many predefined names are listed in < X11/StringDefs.h >. Before you invent a new name, you should make sure there is not already a name that you can use.

A resource class string starts with a capital letter and uses capitalization for compound names (for example,``BorderWidth''). Each resource class string should have a symbolic identifier prefixed with ``XtC'' (for example, XtCBorderWidth). Many predefined classes are listed in < X11/StringDefs.h >.

A resource representation string is spelled identically to the type name (for example, ``TranslationTable''). Each representation string should have a symbolic identifier prefixed with ``XtR'' (for example, XtRTranslationTable). Many predefined representation types are listed in < X11/StringDefs.h >.

New widget classes start with a capital and use upper case for compound words. Given a new class name AbcXyz, you should derive several names:

Additional widget instance structure part name AbcXyzPart.

Complete widget instance structure names AbcXyzRec and _AbcXyzRec.

Widget instance structure pointer type name AbcXyzWidget.

Additional class structure part name AbcXyzClassPart.

Complete class structure names AbcXyzClassRec and _AbcXyzClassRec.

Class structure pointer type name AbcXyzWidgetClass.

Class structure variable abcXyzClassRec.

Class structure pointer variable abcXyzWidgetClass.

Action procedures available to translation specifications should follow the same naming conventions as procedures. That is, they start with a capital letter, and compound names use upper case (for example, ``Highlight'' and ``NotifyClient'').

The symbolic identifiers XtN..., XtC... and XtR... may be implemented as macros, as global symbols, or as a mixture of the two. The (implicit) type of the identifier is String. The pointer value itself is not significant; clients must not assume that inequality of two identifiers implies inequality of the resource name, class, or representation string. Clients should also note that although global symbols permit savings in literal storage in some environments, they also introduce the possibility of multiple definition conflicts when applications attempt to use independently developed widgets simultaneously.

2.3.2. Widget Subclassing in Public .h Files   

The public .h file for a widget class is imported by clients and contains

A reference to the public .h file for the superclass.

Symbolic identifiers for the names and classes of the new resources that this widget adds to its superclass. The definitions should have a single space between the definition name and the value and no trailing space or comment in order to reduce the possibility of compiler warnings from similar declarations in multiple classes.

Type declarations for any new resource data types defined by the class.

The class record pointer variable used to create widget instances.

The C type that corresponds to widget instances of this class.

Entry points for new class methods.

For example, the following is the public .h file for a possible implementation of a Label widget:

     #ifndef LABEL_H

#define LABEL_H
/* New resources */
#define XtNjustify "justify"
#define XtNforeground "foreground"
#define XtNlabel "label"
#define XtNfont "font"
#define XtNinternalWidth "internalWidth"
#define XtNinternalHeight "internalHeight"
/* Class record pointer */
extern WidgetClass labelWidgetClass;
/* C Widget type definition */
typedef struct _LabelRec *LabelWidget;
/* New class method entry points */
extern void LabelSetText();
/* Widget w */
/* String text */
extern String LabelGetText();
/* Widget w */
#endif LABEL_H

The conditional inclusion of the text allows the application to include header files for different widgets without being concerned that they already may be included as a superclass of another widget.

To accommodate operating systems with file name length restrictions, the name of the public .h file is the first ten characters of the widget class. For example, the public .h file for the Constraint widget class is Constraint.h.

The Public .h file for the Command widget is:

     #ifndef _XawCommand_h

#define _XawCommand_h
#include <X11/Xaw/Label.h>
#define XtNhighlightThickness "highlightThickness"
#define XtNshapeStyle "shapeStyle"
#define XtCShapeStyle "ShapeStyle"
#define XtRShapeStyle "ShapeStyle"
#define XtNcornerRoundPercent "cornerRoundPercent"
#define XtCCornerRoundPercent "CornerRoundPercent"
#define XawShapeRectangle XmuShapeRectangle
#define XawShapeOval XmuShapeOval
#define XawShapeEllipse XmuShapeEllipse
#define XawShapeRoundedRectangle XmuShapeRoundedRectangle
extern WidgetClass commandWidgetClass;
typedef struct _CommandClassRec *CommandWidgetClass;
typedef struct _CommandRec *CommandWidget;
#endif /* _XawCommand_h */
/* DON'T ADD STUFF AFTER THIS */

As well, the following is in the file as a comment:

     /* Command widget resources:

Name Class RepType Default Value
---- ----- ------- -------------
accelerators Accelerators AcceleratorTable NULL
ancestorSensitive AncestorSensitive Boolean True
background Background Pixel XtDefaultBackground
backgroundPixmap Pixmap Pixmap XtUnspecifiedPixmap
bitmap Pixmap Pixmap None
borderColor BorderColor Pixel XtDefaultForeground
borderPixmap Pixmap Pixmap XtUnspecifiedPixmap
borderWidth BorderWidth Dimension 1
callback Callback XtCallbackList NULL
colormap Colormap Colormap parent's colormap
cornerRoundPercent CornerRoundPercent Dimension 25
cursor Cursor Cursor None
cursorName Cursor String NULL
depth Depth int parent's depth
destroyCallback Callback XtCallbackList NULL
encoding Encoding UnsignedChar XawTextEncoding8bit
font Font XFontStruct* XtDefaultFont
foreground Foreground Pixel XtDefaultForeground
height Height Dimension text height
highlightThickness Thickness Dimension 0 if shaped, else 2
insensitiveBorder Insensitive Pixmap Gray
internalHeight Height Dimension 2
internalWidth Width Dimension 4
justify Justify XtJustify XtJustifyCenter
label Label String NULL
leftBitmap LeftBitmap Pixmap None
mappedWhenManaged MappedWhenManaged Boolean True
pointerColor Foreground Pixel XtDefaultForeground
pointerColorBackground Background Pixel XtDefaultBackground
resize Resize Boolean True
screen Screen Screen parent's Screen
sensitive Sensitive Boolean True
shapeStyle ShapeStyle ShapeStyle Rectangle
translations Translations TranslationTable see doc or source
width Width Dimension text width
x Position Position 0
y Position Position 0
*/

2.3.3. Widget Subclassing in Private .h Files   

The private .h file for a widget is imported by widget classes that are subclasses of the widget and contains

A reference to the public .h file for the class.

A reference to the private .h file for the superclass.

Symbolic identifiers for any new resource representation types defined by the class. The definitions should have a single space between the definition name and the value and no trailing space or comment.

A structure part definition for the new fields that the widget instance adds to its superclass's widget structure.

The complete widget instance structure definition for this widget.

A structure part definition for the new fields that this widget class adds to its superclass's constraint structure if the widget class is a subclass of Constraint.

The complete constraint structure definition if the widget class is a subclass of Constraint.

Type definitions for any new procedure types used by class methods declared in the widget class part

A structure part definition for the new fields that this widget class adds to its superclass's widget class structure.

The complete widget class structure definition for this widget.

The complete widget class extension structure definition for this widget, if any.

The symbolic constant identifying the class extension version, if any.

The name of the global class structure variable containing the generic class structure for this class.

An inherit constant for each new procedure in the widget class part structure.

For example, the following is the private .h file for a possible Label widget:

     #ifndef LABELP_H

#define LABELP_H
#include <X11/Label.h>
/* New representation types used by the Label widget */
#define XtRJustify "Justify"
/* New fields for the Label widget record */
typedef struct {
/* Settable resources */
Pixel foreground;
XFontStruct *font;
String label;/* text to display */
XtJustify justify;
Dimension internal_width;/* # pixels horizontal border */
Dimension internal_height;/* # pixels vertical border */
/* Data derived from resources */
GC normal_GC;
GC gray_GC;
Pixmap gray_pixmap;
Position label_x;
Position label_y;
Dimension label_width;
Dimension label_height;
Cardinal label_len;
Boolean display_sensitive;
} LabelPart;
/* Full instance record declaration */
typedef struct _LabelRec {
CorePart core;
LabelPart label;
} LabelRec;
/* Types for Label class methods */
typedef void (*LabelSetTextProc)();
/* Widget w */
/* String text */
typedef String (*LabelGetTextProc)();
/* Widget w */
/* New fields for the Label widget class record */
typedef struct {
LabelSetTextProc set_text;
LabelGetTextProc get_text;
XtPointer extension;
} LabelClassPart;
/* Full class record declaration */
typedef struct _LabelClassRec {
CoreClassPart core_class;
LabelClassPart label_class;
} LabelClassRec;
/* Class record variable */
extern LabelClassRec labelClassRec;
#define LabelInheritSetText((LabelSetTextProc)_XtInherit)
#define LabelInheritGetText((LabelGetTextProc)_XtInherit)
#endif LABELP_H

To accommodate operating systems with file name length restrictions, the name of the private .h file is the first nine characters of the widget class followed by a capital P. For example, the private .h file for the Constraint widget class is ConstrainP.h.

Similarly for the Command Widgets Private .h file:

     /*

* CommandP.h - Private definitions for Command widget
*
*/
#ifndef _XawCommandP_h
#define _XawCommandP_h
#include <X11/Xaw/Command.h>
#include <X11/Xaw/LabelP.h>
/***********************************************************************
*
* Command Widget Private Data
*
***********************************************************************/
typedef enum {
HighlightNone,/* Do not highlight. */
HighlightWhenUnset,/* Highlight only when unset, this is to preserve current command widget functionality. */
HighlightAlways/* Always highlight, lets the toggle widget and other subclasses do the right thing. */
} XtCommandHighlight;
/************************************
*
* Class structure
*
***********************************/
/* New fields for the Command widget class record */
typedef struct _CommandClass
{
int makes_compiler_happy; /* not used */
} CommandClassPart;
/* Full class record declaration */
typedef struct _CommandClassRec {
CoreClassPartcore_class;
SimpleClassPartsimple_class;
LabelClassPartlabel_class;
CommandClassPart command_class;
} CommandClassRec;
extern CommandClassRec commandClassRec;
/***************************************
*
* Instance (widget) structure
*
**************************************/
/* New fields for the Command widget record */
typedef struct {
/* resources */
Dimension highlight_thickness;
XtCallbackList callbacks;
/* private state */
Pixmap gray_pixmap;
GC normal_GC;
GC inverse_GC;
Boolean set;
XtCommandHighlighthighlighted;
/* more resources */
int shape_style;
Dimensioncorner_round;
} CommandPart;
/* XtEventsPtr eventTable;*/
/* Full widget declaration */
typedef struct _CommandRec {
CorePart core;
SimplePart simple;
LabelPart label;
CommandPart command;
} CommandRec;
#endif /* _XawCommandP_h */

2.3.4. Widget Subclassing in .c Files   

The .c file for a widget contains the structure initializer for the class record variable, which contains the following parts:

Class information (for example, superclass, class_name, widget_size, class_initialize, and class_inited).

Data constants (for example, resources and num_resources, actions and num_actions, visible_interest, compress_motion, compress_exposure, and version)

Widget operations (for example, initialize, realize, destroy, resize, expose, set_values, accept_focus, and any new operations specific to the widget).

The superclass field points to the superclass global class record, declared in the superclass private .h file. For direct subclasses of the generic core widget, superclass should be initialized to the address of the widgetClassRec structure. The superclass is used for class chaining operations and for inheriting or enveloping a superclass's operations.

The class_name field contains the text name for this class, which is used by the resource manager. For example, the Label widget has the string ``Label''. More than one widget class can share the same text class name. This string must be permanently allocated prior to or during the execution of the class initialization procedure and must not be subsequently deallocated.

The widget_size field is the size of the corresponding widget instance structure (not the size of the class structure).

The version field indicates the toolkit implementation version number and is used for runtime consistency checking of the X Toolkit and widgets in an application. Widget writers must set it to the implementation-defined symbolic value XtVersion in the widget class structure initialization. Those widget writers who believe that their widget binaries are compatible with other implementations of the Intrinsics can put the special value XtVersionDontCheck in the version field to disable version checking for those widgets. If a widget needs to compile alternative code for different revisions of the Intrinsics interface definition, it may use the symbol XtSpecificationRelease. Use of XtVersion allows the Intrinsics implementation to recognize widget binaries that were compiled with older implementations.

The extension field is for future upward compatibility. If the widget programmer adds fields to class parts, all subclass structure layouts change, requiring complete recompilation. To allow clients to avoid recompilation, an extension field at the end of each class part can point to a record that contains any additional class information required.

The .c file also contains the declaration of the global class structure pointer variable used to create instances of the class.


The following is an abbreviated version of the .c file for a Label widget.

     /* Resources specific to Label */

static XtResource resources[] = {
{XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
XtOffset(LabelWidget, label.foreground), XtRString,
XtDefaultForeground},
{XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
XtOffset(LabelWidget, label.font),XtRString,
XtDefaultFont},
{XtNlabel, XtCLabel, XtRString, sizeof(String),
XtOffset(LabelWidget, label.label), XtRString, NULL},
.
.
.
}
/* Forward declarations of procedures */
static void ClassInitialize();
static void Initialize();
static void Realize();
static void SetText();
static void GetText();
.
.
.
/* Class record constant */
LabelClassRec labelClassRec = {
{
/* core_class fields */
/* superclass */ (WidgetClass)&coreClassRec,
/* class_name */ "Label",
/* widget_size */ sizeof(LabelRec),
/* class_initialize */ ClassInitialize,
/* class_part_initialize */ NULL,
/* class_inited */ False,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ Realize,
/* actions */ NULL,
/* num_actions */ 0,
/* resources */ resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ True,
/* compress_exposure */ True,
/* compress_enterleave */ True,
/* visible_interest */ False,
/* destroy */ NULL,
/* resize */ Resize,
/* expose */ Redisplay,
/* set_values */ SetValues,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_offsets */ NULL,
/* tm_table */ NULL,
/* query_geometry */ XtInheritQueryGeometry,
/* display_accelerator */ NULL,
/* extension */ NULL
},
{
/* Label_class fields */
/* get_text */ GetText,
/* set_text */ SetText,
/* extension */ NULL
}
};
/* Class record pointer */
WidgetClass labelWidgetClass = (WidgetClass) &labelClassRec;
/* New method access routines */
void LabelSetText(w, text)
Widget w;
String text;
{
Label WidgetClass lwc = (Label WidgetClass)XtClass(w);
XtCheckSubclass(w, labelWidgetClass, NULL);
*(lwc->label_class.set_text)(w, text)
}
/* Private procedures */
.
.
.

Here is the entire Command.c file from the X11R5 distribution:

     /* $XConsortium: Command.c,v 1.76 91/05/04 19:29:00 converse Exp $ */

/***********************************************************
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Digital or MIT not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
/*
* Command.c - Command button widget
*/
#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xmu/Misc.h>
#include <X11/Xaw/XawInit.h>
#include <X11/Xaw/CommandP.h>
#include <X11/Xmu/Converters.h>
#define DEFAULT_HIGHLIGHT_THICKNESS 2
#define DEFAULT_SHAPE_HIGHLIGHT 32767
/****************************************************************
*
* Full class record constant
*
****************************************************************/
/* Private Data */
static char defaultTranslations[] =
"<EnterWindow>: highlight() \n\
<LeaveWindow>: reset() \n\
<Btn1Down>: set() \n\
<Btn1Up>: notify() unset() ";
#define offset(field) XtOffsetOf(CommandRec, field)
static XtResource resources[] = {
{XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
offset(command.callbacks), XtRCallback, (XtPointer)NULL},
{XtNhighlightThickness, XtCThickness, XtRDimension, sizeof(Dimension),
offset(command.highlight_thickness), XtRImmediate,
(XtPointer) DEFAULT_SHAPE_HIGHLIGHT},
{XtNshapeStyle, XtCShapeStyle, XtRShapeStyle, sizeof(int),
offset(command.shape_style), XtRImmediate, (XtPointer)XawShapeRectangle},
{XtNcornerRoundPercent, XtCCornerRoundPercent,
XtRDimension, sizeof(Dimension),
offset(command.corner_round), XtRImmediate, (XtPointer) 25},
};
#undef offset
static Boolean SetValues();
static void Initialize(), Redisplay(), Set(), Reset(), Notify(), Unset();
static void Highlight(), Unhighlight(), Destroy(), PaintCommandWidget();
static void ClassInitialize();
static Boolean ShapeButton();
static void Realize(), Resize();
static XtActionsRec actionsList[] = {
{"set", Set},
{"notify", Notify},
{"highlight", Highlight},
{"reset", Reset},
{"unset", Unset},
{"unhighlight", Unhighlight}
};

     #define SuperClass ((LabelWidgetClass)&labelClassRec)

CommandClassRec commandClassRec = {
{
(WidgetClass) SuperClass, /* superclass */
"Command", /* class_name */
sizeof(CommandRec), /* size */
ClassInitialize, /* class_initialize */
NULL, /* class_part_initialize */
FALSE, /* class_inited */
Initialize, /* initialize */
NULL, /* initialize_hook */
Realize, /* realize */
actionsList, /* actions */
XtNumber(actionsList), /* num_actions */
resources, /* resources */
XtNumber(resources), /* resource_count */
NULLQUARK, /* xrm_class */
FALSE, /* compress_motion */
TRUE, /* compress_exposure */
TRUE, /* compress_enterleave */
FALSE, /* visible_interest */
Destroy, /* destroy */
Resize, /* resize */
Redisplay, /* expose */
SetValues, /* set_values */
NULL, /* set_values_hook */
XtInheritSetValuesAlmost, /* set_values_almost */
NULL, /* get_values_hook */
NULL, /* accept_focus */
XtVersion, /* version */
NULL, /* callback_private */
defaultTranslations, /* tm_table */
XtInheritQueryGeometry, /* query_geometry */
XtInheritDisplayAccelerator, /* display_accelerator */
NULL /* extension */
}, /* CoreClass fields initialization */
{
XtInheritChangeSensitive /* change_sensitive */
}, /* SimpleClass fields initialization */
{
0, /* field not used */
}, /* LabelClass fields initialization */
{
0, /* field not used */
}, /* CommandClass fields initialization */
};
/* for public consumption */
WidgetClass commandWidgetClass = (WidgetClass) &commandClassRec;
/****************************************************************
*
* Private Procedures
*
****************************************************************/
static GC
Get_GC(cbw, fg, bg)
CommandWidget cbw;
Pixel fg, bg;
{
XGCValues values;
values.foreground = fg;
values.background = bg;
values.font = cbw->label.font->fid;
values.cap_style = CapProjecting;
if (cbw->command.highlight_thickness > 1 )
values.line_width = cbw->command.highlight_thickness;
else
values.line_width = 0;
return XtGetGC((Widget)cbw,
(GCForeground|GCBackground|GCFont|GCLineWidth|GCCapStyle),
&values);
}

     /* ARGSUSED */

static void
Initialize(request, new, args, num_args)
Widget request, new;
ArgList args; /* unused */
Cardinal *num_args; /* unused */
{
CommandWidget cbw = (CommandWidget) new;
int shape_event_base, shape_error_base;
if (cbw->command.shape_style != XawShapeRectangle
&& !XShapeQueryExtension(XtDisplay(new), &shape_event_base,
&shape_error_base))
cbw->command.shape_style = XawShapeRectangle;
if (cbw->command.highlight_thickness == DEFAULT_SHAPE_HIGHLIGHT) {
if (cbw->command.shape_style != XawShapeRectangle)
cbw->command.highlight_thickness = 0;
else
cbw->command.highlight_thickness = DEFAULT_HIGHLIGHT_THICKNESS;
}
cbw->command.normal_GC = Get_GC(cbw, cbw->label.foreground,
cbw->core.background_pixel);
cbw->command.inverse_GC = Get_GC(cbw, cbw->core.background_pixel,
cbw->label.foreground);
XtReleaseGC(new, cbw->label.normal_GC);
cbw->label.normal_GC = cbw->command.normal_GC;
cbw->command.set = FALSE;
cbw->command.highlighted = HighlightNone;
}
static Region
HighlightRegion(cbw)
CommandWidget cbw;
{
static Region outerRegion = NULL, innerRegion, emptyRegion;
XRectangle rect;
if (cbw->command.highlight_thickness == 0 ||
cbw->command.highlight_thickness >
(Dimension) ((Dimension) Min(cbw->core.width, cbw->core.height)/2))
return(NULL);
if (outerRegion == NULL) {
/* save time by allocating scratch regions only once. */
outerRegion = XCreateRegion();
innerRegion = XCreateRegion();
emptyRegion = XCreateRegion();
}
rect.x = rect.y = 0;
rect.width = cbw->core.width;
rect.height = cbw->core.height;
XUnionRectWithRegion( &rect, emptyRegion, outerRegion );
rect.x = rect.y = cbw->command.highlight_thickness;
rect.width -= cbw->command.highlight_thickness * 2;
rect.height -= cbw->command.highlight_thickness * 2;
XUnionRectWithRegion( &rect, emptyRegion, innerRegion );
XSubtractRegion( outerRegion, innerRegion, outerRegion );
return outerRegion;
}

     /***************************

*
* Action Procedures
*
***************************/
/* ARGSUSED */
static void
Set(w,event,params,num_params)
Widget w;
XEvent *event;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
CommandWidget cbw = (CommandWidget)w;
if (cbw->command.set)
return;
cbw->command.set= TRUE;
if (XtIsRealized(w))
PaintCommandWidget(w, (Region) NULL, TRUE);
}
/* ARGSUSED */
static void
Unset(w,event,params,num_params)
Widget w;
XEvent *event;
String *params; /* unused */
Cardinal *num_params;
{
CommandWidget cbw = (CommandWidget)w;
if (!cbw->command.set)
return;
cbw->command.set = FALSE;
if (XtIsRealized(w)) {
XClearWindow(XtDisplay(w), XtWindow(w));
PaintCommandWidget(w, (Region) NULL, TRUE);
}
}
/* ARGSUSED */
static void
Reset(w,event,params,num_params)
Widget w;
XEvent *event;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
CommandWidget cbw = (CommandWidget)w;
if (cbw->command.set) {
cbw->command.highlighted = HighlightNone;
Unset(w, event, params, num_params);
}
else
Unhighlight(w, event, params, num_params);
}
/* ARGSUSED */
static void
Highlight(w,event,params,num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
CommandWidget cbw = (CommandWidget)w;
if ( *num_params == (Cardinal) 0)
cbw->command.highlighted = HighlightWhenUnset;
else {
if ( *num_params != (Cardinal) 1)
XtWarning("Too many parameters passed to highlight action table.");
switch (params[0][0]) {
case 'A':
case 'a':
cbw->command.highlighted = HighlightAlways;
break;
default:
cbw->command.highlighted = HighlightWhenUnset;
break;
}
}
if (XtIsRealized(w))
PaintCommandWidget(w, HighlightRegion(cbw), TRUE);
}

     /* ARGSUSED */

static void
Unhighlight(w,event,params,num_params)
Widget w;
XEvent *event;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
CommandWidget cbw = (CommandWidget)w;
cbw->command.highlighted = HighlightNone;
if (XtIsRealized(w))
PaintCommandWidget(w, HighlightRegion(cbw), TRUE);
}
/* ARGSUSED */
static void
Notify(w,event,params,num_params)
Widget w;
XEvent *event;
String *params; /* unused */
Cardinal *num_params; /* unused */
{
CommandWidget cbw = (CommandWidget)w;
/* check to be sure state is still Set so that user can cancel
the action (e.g. by moving outside the window, in the default
bindings).
*/
if (cbw->command.set)
XtCallCallbackList(w, cbw->command.callbacks, NULL);
}
static void
Destroy(w)
Widget w;
{
CommandWidget cbw = (CommandWidget) w;
/* so Label can release it */
if (cbw->label.normal_GC == cbw->command.normal_GC)
XtReleaseGC( w, cbw->command.inverse_GC );
else
XtReleaseGC( w, cbw->command.normal_GC );
}
static void Realize(w, valueMask, attributes)
Widget w;
Mask *valueMask;
XSetWindowAttributes *attributes;
{
(*commandWidgetClass->core_class.superclass->core_class.realize)
(w, valueMask, attributes);
ShapeButton( (CommandWidget) w, FALSE);
}
static void Resize(w)
Widget w;
{
if (XtIsRealized(w))
ShapeButton( (CommandWidget) w, FALSE);
(*commandWidgetClass->core_class.superclass->core_class.resize)(w);
}

     /************************

* REDISPLAY (DRAW) Repaint the widget window
************************/
/* ARGSUSED */
static void
Redisplay(w, event, region)
Widget w;
XEvent *event;
Region region;
{
PaintCommandWidget(w, region, FALSE);
}
/* Function Name: PaintCommandWidget
* Description: Paints the command widget.
* Arguments: w - the command widget.
* region - region to paint (passed to the superclass).
* change - did it change either set or highlight state?
* Returns: none
*/
static void
PaintCommandWidget(w, region, change)
Widget w;
Region region;
Boolean change;
{
CommandWidget cbw = (CommandWidget) w;
Boolean very_thick;
GC norm_gc, rev_gc;
very_thick = cbw->command.highlight_thickness >
(Dimension)((Dimension) Min(cbw->core.width, cbw->core.height)/2);
if (cbw->command.set) {
cbw->label.normal_GC = cbw->command.inverse_GC;
XFillRectangle(XtDisplay(w), XtWindow(w), cbw->command.normal_GC,
0, 0, cbw->core.width, cbw->core.height);
region = NULL; /* Force label to repaint text. */
}
else
cbw->label.normal_GC = cbw->command.normal_GC;
if (cbw->command.highlight_thickness <= 0)
{
(*SuperClass->core_class.expose) (w, (XEvent *) NULL, region);
return;
}
/*
* If we are set then use the same colors as if we are not highlighted.
*/
if (cbw->command.set == (cbw->command.highlighted == HighlightNone)) {
norm_gc = cbw->command.inverse_GC;
rev_gc = cbw->command.normal_GC;
}
else {
norm_gc = cbw->command.normal_GC;
rev_gc = cbw->command.inverse_GC;
}
if ( !( (!change && (cbw->command.highlighted == HighlightNone)) ||
((cbw->command.highlighted == HighlightWhenUnset) &&
(cbw->command.set))) ) {
if (very_thick) {
cbw->label.normal_GC = norm_gc; /* Give the label the right GC. */
XFillRectangle(XtDisplay(w),XtWindow(w), rev_gc,
0, 0, cbw->core.width, cbw->core.height);
}
else {
/* wide lines are centered on the path, so indent it */
int offset = cbw->command.highlight_thickness/2;
XDrawRectangle(XtDisplay(w),XtWindow(w), rev_gc, offset, offset,
cbw->core.width - cbw->command.highlight_thickness,
cbw->core.height - cbw->command.highlight_thickness);
}
}
(*SuperClass->core_class.expose) (w, (XEvent *) NULL, region);
}

     /*

* Set specified arguments into widget
*/
/* ARGSUSED */
static Boolean
SetValues (current, request, new)
Widget current, request, new;
{
CommandWidget oldcbw = (CommandWidget) current;
CommandWidget cbw = (CommandWidget) new;
Boolean redisplay = False;
if ( oldcbw->core.sensitive != cbw->core.sensitive && !cbw->core.sensitive) {
/* about to become insensitive */
cbw->command.set = FALSE;
cbw->command.highlighted = HighlightNone;
redisplay = TRUE;
}
if ( (oldcbw->label.foreground != cbw->label.foreground) ||
(oldcbw->core.background_pixel != cbw->core.background_pixel) ||
(oldcbw->command.highlight_thickness !=
cbw->command.highlight_thickness) ||
(oldcbw->label.font != cbw->label.font) )
{
if (oldcbw->label.normal_GC == oldcbw->command.normal_GC)
/* Label has release one of these */
XtReleaseGC(new, cbw->command.inverse_GC);
else
XtReleaseGC(new, cbw->command.normal_GC);
cbw->command.normal_GC = Get_GC(cbw, cbw->label.foreground,
cbw->core.background_pixel);
cbw->command.inverse_GC = Get_GC(cbw, cbw->core.background_pixel,
cbw->label.foreground);
XtReleaseGC(new, cbw->label.normal_GC);
cbw->label.normal_GC = (cbw->command.set
? cbw->command.inverse_GC
: cbw->command.normal_GC);
redisplay = True;
}
if ( XtIsRealized(new)
&& oldcbw->command.shape_style != cbw->command.shape_style
&& !ShapeButton(cbw, TRUE))
{
cbw->command.shape_style = oldcbw->command.shape_style;
}
return (redisplay);
}
static void ClassInitialize()
{
XawInitializeWidgetSet();
XtSetTypeConverter( XtRString, XtRShapeStyle, XmuCvtStringToShapeStyle,
NULL, 0, XtCacheNone, NULL );
}
static Boolean
ShapeButton(cbw, checkRectangular)
CommandWidget cbw;
Boolean checkRectangular;
{
Dimension corner_size;
if ( (cbw->command.shape_style == XawShapeRoundedRectangle) ) {
corner_size = (cbw->core.width < cbw->core.height) ? cbw->core.width
: cbw->core.height;
corner_size = (int) (corner_size * cbw->command.corner_round) / 100;
}
if (checkRectangular || cbw->command.shape_style != XawShapeRectangle) {
if (!XmuReshapeWidget((Widget) cbw, cbw->command.shape_style,
corner_size, corner_size)) {
cbw->command.shape_style = XawShapeRectangle;
return(False);
}
}
return(TRUE);
}

2.3.5. Widget Class and Superclass Look Up   

To obtain the class of a widget, use XtClass.


WidgetClass XtClass(w)
Widget w;
w Specifies the widget. Must be of class Object or any subclass thereof.
The XtClass function returns a pointer to the widget's class structure.

To obtain the superclass of a widget, use XtSuperclass.


WidgetClass XtSuperclass(w)
Widget w;
w Specifies the widget. Must be of class Object or any subclass thereof.
The XtSuperclass function returns a pointer to the widget's superclass class structure.

2.3.6. Widget Subclass Verification   

To check the subclass to which a widget belongs, use XtIsSubclass.


Boolean XtIsSubclass(w, widget_class)
Widget w;
WidgetClass widget_class;
w Specifies the widget or object instance whose class is to be checked.
Must be of class Object or any subclass thereof.
widget_class Specifies the widget class for which to test.
Must be objectClass or any subclass thereof.
The XtIsSubclass function returns True if the class of the specified widget is equal to or is a subclass of the specified class. The widget's class can be any number of subclasses down the chain and need not be an immediate subclass of the specified class. Composite widgets that need to restrict the class of the items they contain can use XtIsSubclass to find out if a widget belongs to the desired class of objects.

To test if a given widget belongs to a subclass of an Intrinsics-defined class, the Intrinsics define macros or functions equivalent to XtIsSubclass for each of the built-in classes. These procedures are XtIsObject, XtIsRectObj, XtIsWidget, XtIsComposite, XtIsConstraint, XtIsShell, XtIsOverrideShell, XtIsWMShell, XtIsVendorShell, XtIsTransientShell, XtIsTopLevelShell and XtIsApplicationShell.

All these macros and functions have the same argument description.


Boolean XtIs<class> (w)
Widget w;
w Specifies the widget or object instance whose class is to be checked.
Must be of class Object or any subclass thereof.
These procedures may be faster than calling XtIsSubclass directly for the built-in classes.

To check a widget's class and to generate a debugging error message, use XtCheckSubclass, defined in < X11/IntrinsicP.h >:


void XtCheckSubclass(w, widget_class, message)
Widget w;
WidgetClass widget_class;
String message;
w Specifies the widget or object whose class is to be checked.
Must be of class Object or any subclass thereof.
widget_class Specifies the widget class for which to test.
Must be objectClass or any subclass thereof.
message Specifies the message to be used.
The XtCheckSubclass macro determines if the class of the specified widget is equal to or is a subclass of the specified class. The widget's class can be any number of subclasses down the chain and need not be an immediate subclass of the specified class. If the specified widget's class is not a subclass, XtCheckSubclass constructs an error message from the supplied message, the widget's actual class, and the expected class and calls XtErrorMsg. XtCheckSubclass should be used at the entry point of exported routines to ensure that the client has passed in a valid widget class for the exported operation.

XtCheckSubclass is only executed when the module has been compiled with the compiler symbol DEBUG defined; otherwise, it is defined as the empty string and generates no code.

2.3.7. Superclass Chaining   

While most fields in a widget class structure are self- contained, some fields are linked to their corresponding fields in their superclass structures. With a linked field, the Intrinsics access the field's value only after accessing its corresponding superclass value (called downward superclass chaining) or before accessing its corresponding superclass value (called upward superclass chaining). The self-contained fields are



In all widget classes:
class_name class_initialize widget_size realize tm_table
visible_interest resize expose accept_focus version
compress_motion compress_exposure compress_enterleave set_values_almost

In Composite widget classes:
geometry_manager change_managed insert_child delete_child accepts_objects
In Constraint widget classes:
constraint_size
In Shell widget classes:
root_geometry_manager

With downward superclass chaining, the invocation of an operation first accesses the field from the Object, RectObj, and Core class structures, then from the subclass structure, and so on down the class chain to that widget's class structure.



These superclass-to-subclass fields are
class_part_initialize get_values_hook initialize initialize_hook set_values
set_values_hook resources

In addition, for subclasses of Constraint, the following fields of the ConstraintClassPart and ConstraintClassExtensionRec structures are chained from the Constraint class down to the subclass:



resources initialize set_values get_values_hook

With upward superclass chaining, the invocation of an operation first accesses the field from the widget class structure, then from the superclass structure, and so on up the class chain to the Core, RectObj, and Object class structures. The subclass-to-superclass fields are



destroy actions

For subclasses of Constraint, the following field of ConstraintClassPart is chained from the subclass up to the Constraint class:



destroy

2.3.8. Class Initialization: class_initialize and class_part_initialize Procedures   

Many class records can be initialized completely at compile or link time. In some cases, however, a class may need to register type converters or perform other sorts of once-only runtime initialization.

Because the C language does not have initialization procedures that are invoked automatically when a program starts up, a widget class can declare a class_initialize procedure that will be automatically called exactly once by the Intrinsics. A class initialization procedure pointer is of type XtProc:

    typedef void (*XtProc)(void);

A widget class indicates that it has no class initialization procedure by specifying NULL in the class_initialize field.

In addition to the class initialization that is done exactly once, some classes perform initialization for fields in their parts of the class record. These are performed not just for the particular class but for subclasses as well, and are done in the class's class part initialization procedure, a pointer to which is stored in the class_part_initialize field. The class_part_initialize procedure pointer is of type XtWidgetClassProc.


typedef void (*XtWidgetClassProc)(WidgetClass);
WidgetClass widget_class;
widget_class Points to the class structure for the class being initialized.
During class initialization, the class part initialization procedures for the class and all its superclasses are called in superclass-to-subclass order on the class record. These procedures have the responsibility of doing any dynamic initializations necessary to their class's part of the record. The most common is the resolution of any inherited methods defined in the class. For example, if a widget class C has superclasses Core, Composite, A, and B, the class record for C first is passed to Core 's class_part_initialize procedure. This resolves any inherited Core methods and compiles the textual representations of the resource list and action table that are defined in the class record. Next, Composite's class_part_initialize procedure is called to initialize the composite part of C's class record. Finally, the class_part_initialize procedures for A, B, and C, in that order, are called. Classes that do not define any new class fields or that need no extra processing for them can specify NULL in the class_part_initialize field.

All widget classes, whether they have a class initialization procedure or not, must start with their class_inited field False.

The first time a widget of a class is created, XtCreateWidget ensures that the widget class and all superclasses are initialized, in superclass-to-subclass order, by checking each class_inited field and, if it is False , by calling the class_initialize and the class_part_initialize procedures for the class and all its superclasses. The Intrinsics then set the class_inited field to a nonzero value. After the one-time initialization, a class structure is constant.

The following example provides the class initialization procedure for a Label class.

     static void ClassInitialize()

{
XtSetTypeConverter(XtRString, XtRJustify, CvtStringToJustify,
NULL, 0, XtCacheNone, NULL);
}

2.3.9. Initializing a Widget Class   

A class is initialized when the first widget of that class or any subclass is created. To initialize a widget class without creating any widgets, use XtInitializeWidgetClass.


void XtInitializeWidgetClass(object_class)
WidgetClass object_class;
object_class Specifies the object class to initialize.
May be objectClass or any subclass thereof.
If the specified widget class is already initialized, XtInitializeWidgetClass returns immediately.

If the class initialization procedure registers type converters, these type converters are not available until the first object of the class or subclass is created or XtInitializeWidgetClass is called.

2.3.10. Inheritance of Superclass Operations   

A widget class is free to use any of its superclass's self- contained operations rather than implementing its own code. The most frequently inherited operations are



expose realize insert_child delete_child geometry_manager
set_values_almost

To inherit an operation xyz, specify the constant XtInheritXyz in your class record.

Every class that declares a new procedure in its widget class part must provide for inheriting the procedure in its class_part_initialize procedure. The chained operations declared in Core and Constraint records are never inherited. Widget classes that do nothing beyond what their superclass does specify NULL for chained procedures in their class records.

Inheriting works by comparing the value of the field with a known, special value and by copying in the superclass's value for that field if a match occurs. This special value, called the inheritance constant, is usually the Intrinsics internal value _XtInherit cast to the appropriate type. _XtInherit is a procedure that issues an error message if it is actually called.

For example, CompositeP.h contains these definitions:

  #define XtInheritGeometryManager ((XtGeometryHandler) _XtInherit)

#define XtInheritChangeManaged ((XtWidgetProc) _XtInherit)
#define XtInheritInsertChild ((XtArgsProc) _XtInherit)
#define XtInheritDeleteChild ((XtWidgetProc) _XtInherit)

Composite's class_part_initialize procedure begins as follows:

     static void CompositeClassPartInitialize(widgetClass)

WidgetClass widgetClass;
{
CompositeWidgetClass wc = (CompositeWidgetClass)widgetClass;
CompositeWidgetClass super = (CompositeWidgetClass)wc->core_class.superclass;
if (wc->composite_class.geometry_manager == XtInheritGeometryManager) {
wc->composite_class.geometry_manager = super->composite_class.geometry_manager;
}
if (wc->composite_class.change_managed == XtInheritChangeManaged) {
wc->composite_class.change_managed = super->composite_class.change_managed;
}
.
.
.

Nonprocedure fields may be inherited in the same manner as procedure fields. The class may declare any reserved value it wishes for the inheritance constant for its new fields. The following inheritance constants are defined:


For Core:
XtInheritRealize XtInheritResize XtInheritExpose XtInheritSetValuesAlmost
XtInheritAcceptFocus XtInheritQueryGeometry XtInheritTranslations XtInheritDisplayAccelerator


For Composite:
XtInheritGeometryManager XtInheritChangeManaged XtInheritInsertChild XtInheritDeleteChild


For Shell:
XtInheritRootGeometryManager

2.3.11. Invocation of Superclass Operations   

A widget sometimes needs to call a superclass operation that is not chained. For example, a widget's expose procedure might call its superclass's expose and then perform a little more work on its own. For example, a Composite class with predefined managed children can implement insert_child by first calling its superclass's insert_child and then calling XtManageChild to add the child to the managed set.


A class method should not use XtSuperclass but should instead call the class method of its own specific superclass directly through the superclass record. That is, it should use its own class pointers only, not the widget's class pointers, as the widget's class may be a subclass of the class whose implementation is being referenced.


This technique is referred to as enveloping the superclass's operation.

2.3.12. Class Extension Records   

It may be necessary at times to add new fields to already existing widget class structures. To permit this to be done without requiring recompilation of all subclasses, the last field in a class part structure should be an extension pointer. If no extension fields for a class have yet been defined, subclasses should initialize the value of the extension pointer to NULL.

If extension fields exist, as is the case with the Composite, Constraint and Shell classes, subclasses can provide values for these fields by setting the extension pointer for the appropriate part in their class structure to point to a statically declared extension record containing the additional fields. Setting the extension field is never mandatory; code that uses fields in the extension record must always check the extension field and take some appropriate default action if it is NULL.

In order to permit multiple subclasses and libraries to chain extension records from a single extension field, extension records should be declared as a linked list and each extension record definition should contain the following four fields at the beginning of the structure declaration:


struct {
XtPointer next_extension;
XrmQuark record_type;
long version;
Cardinal record_size;
};
next_extension. Specifies the next record in the list, or NULL.
record_type. Specifies the particular structure declaration to which each extension record instance conforms.
version. Specifies a version id symbolic constant supplied by the definer of the structure.
record_size 1. Specifies the total number of bytes allocated for the extension record.
The record_type field identifies the contents of the extension record and is used by the definer of the record to locate its particular extension record in the list. The record_type field is normally assigned the result of XrmStringToQuark for a registered string constant. The Intrinsics reserve all record type strings beginning with the two characters ``XT'' for future standard uses. The value NULLQUARK may also be used by the class part owner in extension records attached to its own class part extension field to identify the extension record unique to that particular class.

The version field is an owner-defined constant that may be used to identify binary files that have been compiled with alternate definitions of the remainder of the extension record data structure. The private header file for a widget class should provide a symbolic constant for subclasses to use to initialize this field. The record_size field value includes the four common header fields and should normally be initialized with sizeof().

Any value stored in the class part extension fields of CompositeClassPart, ConstraintClassPart, or ShellClassPart must point to an extension record conforming to this definition.

2.3.13. Widget Instantiation   

A hierarchy of widget instances constitutes a widget tree. The shell widget returned by XtAppCreateShell is the root of the widget tree instance. The widgets with one or more children are the intermediate nodes of that tree, and the widgets with no children of any kind are the leaves of the widget tree. With the exception of pop-up children, this widget tree instance defines the associated X Window tree.

Widgets can be either composite or primitive. Both kinds of widgets can contain children, but the Intrinsics provide a set of management mechanisms for constructing and interfacing between composite widgets, their children, and other clients.

Composite widgets, that is, members of the class compositeWidgetClass, are containers for an arbitrary but widget implementation-defined collection of children, which may be instantiated by the composite widget itself, by other clients, or by a combination of the two. Composite widgets also contain methods for managing the geometry (layout) of any child widget. Under unusual circumstances, a composite widget may have zero children, but it usually has at least one. By contrast, primitive widgets that contain children typically instantiate specific children of known classes themselves and do not expect external clients to do so. Primitive widgets also do not have general geometry management methods.

In addition, the Intrinsics recursively perform many operations (for example, realization and destruction) on composite widgets and all their children. Primitive widgets that have children must be prepared to perform the recursive operations themselves on behalf of their children.

A widget tree is manipulated by several Intrinsics functions. For example, XtRealizeWidget traverses the tree downward and recursively realizes all pop-up widgets and children of composite widgets. XtDestroyWidget traverses the tree downward and destroys all pop-up widgets and children of composite widgets. The functions that fetch and modify resources traverse the tree upward and determine the inheritance of resources from a widget's ancestors. XtMakeGeometryRequest traverses the tree up one level and calls the geometry manager that is responsible for a widget child's geometry.

To facilitate upward traversal of the widget tree, each widget has a pointer to its parent widget. The Shell widget that XtAppCreateShell returns has a parent pointer of NULL.

To facilitate downward traversal of the widget tree, the children field of each composite widget is a pointer to an array of child widgets, which includes all normal children created, not just the subset of children that are managed by the composite widget's geometry manager. Primitive widgets that instantiate children are entirely responsible for all operations that require downward traversal below themselves. In addition, every widget has a pointer to an array of pop-up children.

2.3.14. Creating a Widget Instance   

To create an instance of a widget, use XtCreateWidget.


Widget XtCreateWidget(name, object_class, parent, args, num_args)
String name;
WidgetClass object_class;
Widget parent;
ArgList args;
Cardinal num_args;
name Specifies the resource instance name for the created widget,
which is used for retrieving resources and, for that reason, should not be the same as any other widget
that is a child of the same parent.
object_class Specifies the widget class pointer for the created object.
Must be objectClass or any subclass thereof.
parent Specifies the parent widget. Must be of class Object or any subclass thereof.
args Specifies the argument list to override any other resource specifications.
num_args Specifies the number of entries in the argument list.
The XtCreateWidget function performs all the boilerplate operations of widget creation, doing the following in order:

Checks to see if the class_initialize procedure has been called for this class and for all superclasses and, if not, calls those necessary in a superclass-to-subclass order.

If the specified class is not coreWidgetClass or a subclass thereof, and the parent's class is a subclass of compositeWidgetClass and either no extension record in the parent's composite class part extension field exists with the record_type NULLQUARK or the accepts_objects field in the extension record is False, XtCreateWidget issues a fatal error.

Allocates memory for the widget instance.

If the parent is a member of the class constraintWidgetClass, allocates memory for the parent's constraints and stores the address of this memory into the constraints field.

Initializes the Core nonresource data fields (for example, parent and visible).

Initializes the resource fields (for example, background_pixel) by using the CoreClassPart resource lists specified for this class and all superclasses.

If the parent is a member of the class constraintWidgetClass, initializes the resource fields of the constraints record by using the ConstraintClassPart resource lists specified for the parent's class and all superclasses up to constraintWidgetClass.

Calls the initialize procedures for the widget starting at the Object initialize procedure on down to the widget's initialize procedure.

If the parent is a member of the class compositeWidgetClass, puts the widget into its parent's children list by calling its parent's insert_child procedure.

If the parent is a member of the class constraintWidgetClass, calls the ConstraintClassPart initialize procedures, starting at constraintWidgetClass on down to the parent's ConstraintClassPart initialize procedure.

To create an instance of a widget using varargs lists, use XtVaCreateWidget.


Widget XtVaCreateWidget(name, object_class, parent, ...)
String name;
WidgetClass object_class;
Widget parent;
name Specifies the resource name for the created widget.
object_class Specifies the widget class pointer for the created object.
Must be objectClass or any subclass thereof.
parent Specifies the parent widget. Must be of class Object or any subclass thereof.
... Specifies the variable argument list to override any other resource specifications.
The XtVaCreateWidget procedure is identical in function to XtCreateWidget with the args and num_args parameters replaced by a varargs list.

2.3.15. Widget Instance Initialization: the initialize Procedure   

The initialize procedure pointer in a widget class is of type XtInitProc.


typedef void (*XtInitProc)(Widget, Widget, ArgList, Cardinal*);
Widget request;
Widget new;
ArgList args;
Cardinal *num_args;
request Specifies a copy of the widget with resource values as requested by the
argument list, the resource database, and the widget defaults.
new Specifies the widget with the new values, both resource and nonresource,
that are actually allowed.
args Specifies the argument list passed by the client, for computing derived resource values.
If the client created the widget using a varargs form, any resources specified via XtVaTypedArg
are converted to the widget representation and the list is transformed into the ArgList format.
num_args Specifies the number of entries in the argument list.
An initialization procedure performs the following:

Allocates space for and copies any resources referenced by address that the client is allowed to free or modify after the widget has been created. For example, if a widget has a field that is a String, it may choose not to depend on the characters at that address remaining constant but dynamically allocate space for the string and copy it to the new space. Widgets that do not copy one or more resources referenced by address should clearly so state in their user documentation.
It is not necessary to allocate space for or to copy callback lists.

Computes values for unspecified resource fields. For example, if width and height are zero, the widget should compute an appropriate width and height based on its other resources.
A widget may only directly assign its own width and height within the initialize, initialize_hook, set_values and set_values_hook procedures.

Computes values for uninitialized nonresource fields that are derived from resource fields. For example, graphics contexts (GCs) that the widget uses are derived from resources like background, foreground, and font.

An initialization procedure also can check certain fields for internal consistency. For example, it makes no sense to specify a colormap for a depth that does not support that colormap.

Initialization procedures are called in superclass-to- subclass order after all fields specified in the resource lists have been initialized. The initialize procedure does not need to examine args and num_args if all public resources are declared in the resource list. Most of the initialization code for a specific widget class deals with fields defined in that class and not with fields defined in its superclasses.

If a subclass does not need an initialization procedure because it does not need to perform any of the above operations, it can specify NULL for the initialize field in the class record.

Sometimes a subclass may want to overwrite values filled in by its superclass. In particular, size calculations of a superclass are often incorrect for a subclass, and in this case, the subclass must modify or recalculate fields declared and computed by its superclass.

As an example, a subclass can visually surround its superclass display. In this case, the width and height calculated by the superclass initialize procedure are too small and need to be incremented by the size of the surround. The subclass needs to know if its superclass's size was calculated by the superclass or was specified explicitly. All widgets must place themselves into whatever size is explicitly given, but they should compute a reasonable size if no size is requested.

The request and new arguments provide the necessary information for a subclass to determine the difference between an explicitly specified field and a field computed by a superclass. The request widget is a copy of the widget as initialized by the arglist and resource database. The new widget starts with the values in the request, but it has been updated by all superclass initialization procedures called so far. A subclass initialize procedure can compare these two to resolve any potential conflicts.

In the above example, the subclass with the visual surround can see if the width and height in the request widget are zero. If so, it adds its surround size to the width and height fields in the new widget. If not, it must make do with the size originally specified.

The new widget will become the actual widget instance record. Therefore, the initialization procedure should do all its work on the new widget; the request widget should never be modified. If the initialize procedure needs to call any routines that operate on a widget, it should specify new as the widget instance.

2.3.16. Constraint Instance Initialization: the ConstraintClassPart initialize Procedure   

The constraint initialization procedure pointer, found in the ConstraintClassPart initialize field of the widget class record, is of type XtInitProc. The values passed to the parent constraint initialization procedures are the same as those passed to the child's class widget initialization procedures.

The constraints field of the request widget points to a copy of the constraints record as initialized by the arglist and resource database.

The constraint initialization procedure should compute any constraint fields derived from constraint resources. It can make further changes to the new widget to make the widget and any other constraint fields conform to the specified constraints, for example, changing the widget's size or position.

If a constraint class does not need a constraint initialization procedure, it can specify NULL for the initialize field of the ConstraintClassPart in the class record.

2.3.17. Nonwidget Data Initialization: the initialize_hook Procedure   

The initialize_hook procedure is obsolete, as the same information is now available to the initialize procedure. The procedure has been retained for those widgets that used it in previous releases.

The initialize_hook procedure pointer is of type XtArgsProc:


typedef void (*XtArgsProc)(Widget, ArgList, Cardinal*);
Widget w;
ArgList args;
Cardinal *num_args;
w Specifies the widget.
args Specifies the argument list passed by the client.
If the client created the widget using a varargs form, any resources specified via XtVaTypedArg
are converted to the widget representation and the list is transformed into the ArgList format.
num_args Specifies the number of entries in the argument list.
If this procedure is not NULL, it is called immediately after the corresponding initialize procedure or in its place if the initialize field is NULL.

The initialize_hook procedure allows a widget instance to initialize nonresource data using information from the specified argument list as if it were a resource.