Chapter 4. The Widget Class Record of Manager Widgets

This chapter explains how to write a class record for subclasses of the XmManager widget. As shown in Figure 4-1, the manager widgets you write will descend from the Core, Composite, Constraint, and XmManager widgets.

Figure 4-1. Class Hierarchy of Manager Widgets

Therefore, the class record of a manager widget must consist of:

This chapter details all these fields from a Motif widget writer's perspective. In addition, this chapter describes the data members of XmManager that are accessible to your widget.

The CoreClassPart Structure

Your manager widget must contain a class record. The first portion of the class record is a CoreClassPart structure. For example, following is the CoreClassPart structure of the ExmGrid widget:

externaldef(exmgridclassrec) ExmGridClassRec exmGridClassRec =
{
  {                     /* core_class */
    /* superclass */                 (WidgetClass) &xmManagerClassRec,
    /* class_name */                 "ExmGrid",
    /* widget_size */                sizeof(ExmGridRec),
    /* class_initialize */           NULL,
    /* class_part_initialize */      ClassPartInitialize,
    /* class_inited */               FALSE,
    /* initialize */                 Initialize,
    /* initialize_hook */            NULL,
    /* realize */                    XtInheritRealize,
    /* actions */                    NULL,
    /* num_actions */                0,
    /* resources */                  resources,
    /* num_resources */              XtNumber(resources),
    /* xrm_class */                  NULLQUARK,
    /* compress_motion */            TRUE,
    /* compress_exposure */          XtExposeCompressMaximal,
    /* 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_private */           NULL,
    /* tm_table */                   XtInheritTranslations,
    /* query_geometry */             QueryGeometry,
    /* display_accelerator */        NULL,
    /* extension */                  NULL,
  },

The following subsections explain what Motif widget writers need to know about these fields.

The superclass Field

The first field of the CoreClassPart structure is the superclass field. For this field, you must specify the name of the class record of your widget's immediate superclass. For example, if your widget's immediate superclass is XmManager, the superclass field will look as follows:

/* superclass */                 (WidgetClass) &xmManagerClassRec,

The class_name Field

The class_name field holds a string representing the name of the class; for example:

/* class_name */                 "ExmGrid",

Motif will not make any attempt to interpret the characters in the string. The string can be any length, and can be composed of alphanumeric character, hypens, and underbars.

The string should begin with some prefix that uniquely symbolizes the widget group you are creating. For example, all the sample widgets associated with this group start with the Exm prefix. Do not pick a prefix that is used by other groups. For example, Motif reserves the prefixes xm, Xm, _Xm, Xme, XmQT, and Exm. See Chapter 2 for more information on namespace.

The widget_size Field

The widget_size field of manager widgets holds the size of the full instance record. For example, the full instance record of the ExmGrid demonstration widget is named ExmGridRec; therefore, the Core class record of ExmGrid defines the widget_size field as follows:

/* widget_size */                sizeof(ExmGridRec);

The class_initialize Field

The Intrinsics call the class_initialize method only once, at the first instantiation of a widget of this class. You can set the class_initialize field to one of the following:

  • The name of your widget's class_initialize method.

  • NULL, to indicate the absence of a class initialization method. (About half the standard Motif manager widgets set this field to NULL.)

Motif makes no requirements of the code in class_initialize methods. However, Motif recommends registering any new representation types inside the class_initialize method. (See Chapter 6 for details.)

The class_part_initialize Field (Chained)

The Intrinsics call the class_part_initialize method at the first instantiation of a widget of this class or of a subclass of this class. You can set the class_part_initialize field to one of the following:

  • The name of your widget's class_part_initialize method.

  • NULL, indicating the absence of a class_part_initialize method.

The class_part_initialize method is chained; therefore, the Intrinsics call the class_part_initialize method of Core, Composite, Constraint, and XmManager before calling the class_part_initialize method of your own widget. (See documentation on the Intrinsics for information on the class_part_initialize methods of Core, Composite, and Constraint.) The class_part_initialize method of XmManager does the following:

  • If your widget does not specify a Composite class extension record, XmManager creates one for you by copying the Composite class extension record of your widget's superclass.

  • If your widget does not specify an XmManager class extension record, XmManager creates one for you by copying the XmManager class extension record of your widget's superclass.

  • Initializes synthetic resource management

  • Establishes the class translations field, if your widget specifies XtInheritTranslations

Motif makes no requirements of the code in your widget's class_part_initialize method. However, most Motif widgets use this method to install traits. (See Chapter 5 for details on installing traits.)

The class_inited Field

Motif widgets must always set the value of the class_inited field to False.

The initialize Field (Chained)

The Intrinsics call your widget's initialize method when an application instantiates your widget. You must specify one of the following:

  • The name of your initialize method

  • NULL, to indicate the absence of an initialize method.

The initialize method is chained; therefore, the Intrinsics call the initialize method of the Core, Composite, Constraint, and XmManager widgets before calling the initialize method of your own widget. (See documentation on the Intrinsics for details on the initialize method of Core, Composite, and Constraint.) The initialize method of XmManager does the following:

  • Initializes values for certain instance data members of XmManager.

  • Validates the XmNnavigationType, XmNstringDirection, and XmNunitType resources.

  • Merges the keyboard traversal translations (specified in the translations field) with the regular widget translations (specified in the tm_table field). The initialize method places the traversal translations at the top of the translations table. Therefore, if a keyboard traversal translation and a regular widget translation both define an action for the same virtual key, then the action of the keyboard traversal translation takes precedence.

  • Initializes keyboard traversal.

  • Establishes synthetic resources.

  • Creates four GCs—manager.highlight_GC, manager.top_shadow_GC, manager.bottom_shadow_GC , and manager.background_GC—by calling GC creation methods stored in XmManager.

  • Provides a mechanism for automatic inheritance of accelerators.

The code in your own initialize method should check resource values and perform other start-up tasks relevant to your widget's creation. You can find a sample initialize method for a manager widget inside the Grid.c file.

The initialize_hook Field (Chained)

The initialize_hook field is obsolete. Motif ignores the stored value of this field; set it to NULL.

The realize Field

The realize field holds the name of the method that is responsible for creating the widget's window. If you want a standard Motif manager window, you should inherit the realize method of the XmManager widget by setting the realize field to XtInheritRealize.

The realize method of XmManager calls XtCreateWindow to create a window. It is impossible for the width or height of the created window to be 0. Therefore, if the widget does not yet have a width or height, the realize method of XmManager forces the width or height to 1 pixel.

The window class of the created window will be InputOutput. The generated window will not propagate any button, key, or pointer motion events to its parent window(s).

The default windows for managers and primitives use bit gravity differently. Default manager windows set bit gravity to NorthWest, while default primitive windows take the default bit gravity, ForgetGravity.

The Motif Style Guide does not demand that all windows conform to a certain standard. For that matter, the Motif Style Guide does not even insist that all windows be rectangular. Therefore, you are free to create your own realize method.

The actions Field

Specify the name of the array that holds the actions methods defined by your widget. (See Chapter 7 for details on actions.)

The num_actions Field

The num_actions field holds the number of actions defined by the array in the actions field. If your widget does not provide an actions array, then you should specify 0 for the num_actions field. If your widget does provide an actions array, then you should use the XtNumber macro to count these actions. For example, the ExmCommandButton widget does provide an actions array, so its num_actions field looks as follows:

/* num_actions */                XtNumber(actions),

The resources Field

If your widget defines new resources, specify the name of the resources array. If your widget does not define new resources, specify NULL.

Your widget will automatically inherit the resources of its superclasses. (See Chapter 6 for more details on resources.)

The num_resources Field

The num_resources field holds the number of resources defined by the array in the resources field. If your widget does not provide a resources array, then you should specify 0 for the num_resources field. If your widget does provide a resources array, then your widget should use the XtNumber macro to count these resources. For example, the ExmGrid widget does provide a resources array, so its num_resources field looks as follows:

/* num_resources */                XtNumber(resources),

The xrm_class Field

Your widget must always specify NULLQUARK as the value of the xrm_class field.

The compress_motion Field

The compress_motion field requires a Boolean value. Setting this value to True eliminates certain redundant pointer motion events from the event queue. Setting this value to False imposes a slight performance penalty but produces more accurate pointer tracking. (See documentation on the Intrinsics for more details.)

Every standard Motif manager widget sets the compress_motion field to True.

The compress_exposure Field

The compress_exposure field requires a constant value. This value tells the Intrinsics how to respond to multiple exposure events. (See documentation on the Intrinsics for more complete details.)

Motif makes no recommendations on the value of the compress_exposure field. The XmManager widget sets this field to XtExposeCompressMaximal.

Managers that may have gadget children should not use the XtExposeNoRegion flag.

The compress_enterleave Field

The compress_enterleave field requires a Boolean value. Setting this value to True means that the Intrinsics will ignore unimportant enter event/leave event pairs. (See documentation on the Intrinsics for more complete details.)

Motif makes no recommendations on the value of the compress_enterleave field. However, most standard Motif manager widgets, including the XmManager widget, set this field to True.

The visible_interest Field

The visible_interest field requires a Boolean value. This value provides hints to the Intrinsics on the redisplay of partially exposed widgets. Motif does not layer any extra meaning on top of the standard Intrinsics use of this field.

Motif makes no recommendations on the value of this field. However, every standard Motif widget sets this field to False.

The destroy Field (Chained)

The Intrinsics automatically call the destroy method when the widget is explicitly destroyed. You must specify one of the following:

  • The name of your destroy method

  • NULL, to indicate the absence of a destroy method

The destroy field is chained in subclass-to-superclass order; therefore, the destroy method of XmManager will be called after any destroy method that your own widget supplies. The destroy method of XmManager deallocates the following four graphics contexts:

  • manager.top_shadow_GC

  • manager.bottom_shadow_GC

  • manager.highlight_GC

  • manager.background_GC

In addition, the destroy method of XmManager deallocates all the widget traversal information held by this widget.

If your widget provides a destroy method, make sure it deallocates all strings, fonts, GCs, and so forth, allocated by your widget.

The resize Field

The Intrinsics automatically call the method specified in the resize field in response to a resize event. The XmManager widget does not provide a resize method, so your widget will not be able to inherit a resize method from XmManager. (See Chapter 12 for more information on geometry management.)

The expose (Redisplay) Field

The Intrinsics automatically invoke the expose method upon receiving an exposure event. The interpretation of exposure events can be altered by the values of the compress_exposure and visible_interest fields. (See documentation on the Intrinsics for complete details.)

Your widget should set the expose field to one of the following:

  • XtInheritExpose, to indicate that you are inheriting the expose method of your superclass. However, the XmManager widget does not provide an expose method, so your widget cannot inherit from it.

  • The name of your widget's expose method. If you do provide an expose method, you should name it Redisplay.

All standard Motif manager widgets except XmManager provide their own expose method. Motif requires that your Redisplay method (or the Redisplay method your widget inherits) call XmeRedisplayGadgets in order to pass exposure events down to gadget children. (See Chapter 17 for syntactic details on XmeRedisplayGadgets.)

The set_values Field (Chained)

You can either specify the name of your widget's set_values method or you can specify NULL, which symbolizes the absence of a set_values method. Most of the widgets you write will specify a set_values method.

When an application calls XtSetValues to change any of the resource values in your widget, the Intrinsics automatically call the set_values method.

Your widget's set_values method is responsible for validating changes to resource values. Your widget can call XmRepTypeValidValue to validate changes to representation type resources. (See Chapter 6 for details.)

The code in a set_values method is usually quite similar to the code in an initialize method.

The set_values method returns a Boolean value. The Intrinsics monitor this returned value. If the returned value is True, the Intrinsics automatically invoke the widget's expose (Redisplay) method. There are many reasons why widget redisplay could benecessary. One subtle reason is that a widget GC has changed.

The set_values method is chained. Therefore, the Intrinsics will call the set_values method of XmManager prior to calling the set_values method of your own widget. The set_values method of XmManager does the following:

  • Validates changes to XmNinitialFocus, XmNnavigationType, XmNunitType, and XmNstringDirection.

  • Updates keyboard traversals.

  • Examines the manager.highlight_color and manager.highlight_pixmap fields. If either field's value has changed, set_values destroys the existing manager.highlight_GC and then creates a new one from the updated values. If either field's value has changed, set_values sets its return value to True.

  • Examines the manager.top_shadow_color and manager.top_shadow_pixmap fields. If either field's value has changed, set_values destroys the existing manager.top_shadow_GC and then creates a new one from the updated values. If either field's value has changed, set_values sets its return value to True.

  • Examines the manager.bottom_shadow_color and manager.bottom_shadow_pixmap fields. If either field's value has changed, set_values destroys the existing manager.bottom_shadow_GC and then creates a new one from the updated values. If either field's value has changed, set_values sets its return value to True.

  • Examines the values of the manager.background_pixel or manager.background_pixmap fields. If either field's value has changed, set_values destroys the existing manager.background_GC and then creates a new one from the updated values. If either field's value has changed, set_values sets its return value to True.

  • Checks the values of the GCs of any gadget children of the widget.

  • Determines if any visual changes have occurred in your manager widget. If any have, the set_values method calls the redraw trait method of any child widget that has the XmQTcareParentVisual trait installed. If your manager widget needs to be redrawn as a result of this call, set_values sets its return value to True.

The set_values_hook Field (Chained)

The set_values_hook field is obsolete. Motif ignores its value; set it to NULL.

The set_values_almost Field

The Intrinsics call the method named in the set_values_almost field when certain geometry requests cannot be fulfilled by the geometry manager. To inherit the set_values_almost method of your superclass, specify XtInheritSetValuesAlmost. The XmManager widget itself sets the set_values_almost field to XtInheritSetValuesAlmost, so it inherits this field from the Intrinsics widgets.

Motif makes no requirements for this method. However, all the standard Motif manager widgets set this field to XtInheritSetValuesAlmost. (See Chapter 12 for details on Motif geometry management.)

The get_values_hook Field (Chained)

The get_values_hook field holds the name of a method responsible for returning resource values from any subparts of your widget. If your widget has no need to do this, it should set the get_values_hook field to NULL.

The get_values_hook field is chained; therefore, the Intrinsics will call the get_values_hook method of XmManager prior to the get_values_hook method of your widget. The get_values_hook method of XmManager implements synthetic resources on manager widgets.

The accept_focus Field

Motif ignores the value of the accept_focus field; set it to NULL.

The version Field

The version field holds an enumerated constant pertaining to the compatibility of the Intrinsics themselves. The version field does not express any information regarding Motif compatibility, nor does Motif seek to interpret the version field in any way.

Most widgets set this field to XtVersion. However, if you do not want your widget to check binary compatibility with future releases of the Intrinsics, set this field to XtVersionDontCheck. (See Chapter 15 for details on binary compatibility.)

The callback_private Field

Motif ignores the value of the callback_private field; set it to NULL.

The tm_table Field

You should specify one of the following three possible values for the tm_table field:

  • XtInheritTranslations, to inherit the tm_table string of your widget's immediate superclass.

  • The name of your own tm_table string to provide tm_table translations specific to your widget.

  • NULL, to indicate the absence of any tm_table string translations.

If your tm_table field is set to XtInheritTranslations and your widget's immediate superclass is XmManager, then your widget will inherit the following tm_table translations:

<BtnMotion>: ManagerGadgetButtonMotion()\n\
c<Btn1Down>: ManagerGadgetTraverseCurrent()\n\
~c<Btn1Down>: ManagerGadgetArm()\n\
~c<Btn1Down>,~c<Btn1Up>: ManagerGadgetActivate()\n\
~c<Btn1Up>: ManagerGadgetActivate()\n\
~c<Btn1Down>(2+): ManagerGadgetMultiArm()\n\
~c<Btn1Up>(2+): ManagerGadgetMultiActivate()\n\
<Btn2Down>: ManagerGadgetDrag()\n\
:<Key>osfActivate: ManagerParentActivate()\n\
:<Key>osfCancel: ManagerParentCancel()\n\
:<Key>osfSelect: ManagerGadgetSelect()\n\
:<Key>osfHelp: ManagerGadgetHelp()\n\
~s ~m ~a <Key>Return: ManagerParentActivate()\n\
~s ~m ~a <Key>space: ManagerGadgetSelect()\n\
<Key>: ManagerGadgetKeyInput()";

Suppose you provide your own tm_table string rather than inherit the tm_table string of XmManager. If you want your manager widget to handle the default button events correctly, then your tm_table string should be a superset of the activation translations of XmManager. That is, your tm_table string should contain the following:

:<Key>osfActivate: ManagerParentActivate()\n\
:<Key>osfCancel: ManagerParentCancel()\n\
~s ~m ~a <Key>Return: ManagerParentActivate()\n\

If you want your manager widget to support gadgets properly, then the tm_table string should specify all of the translations used by XmManager.

(See Chapter 7 for more details on translations.)

The query_geometry Field

When your manager is itself a child of another manager widget, the parent manager widget will call your widget's query_geometry method to request your widget's geometry preferences.

Your widget must specify one of the following for the query_geometry field:

  • The name of your widget's query_geometry method.

  • XtInheritQueryGeometry to inherit the query_geometry method of your widget's immediate superclass.

    The XmManager widget does not provide a query_geometry method. Therefore, your widget cannot inherit from it.

  • NULL, to indicate the absence of a query_geometry method. Motif does not recommend this.

(See Chapter 12 for details on Motif geometry management.)

The display_accelerator Field

Motif ignores the value of the display_accelerator field; set it to NULL.

The extension Field

Motif strongly recommends that you set the value of the extension field to NULL. By doing so, Motif will install the correct extension record for you at runtime.

The CompositeClassPart Structure

The second part of the class record is the CompositeClassPart structure. For example, following is the CompositeClassPart structure of the ExmGrid widget:

{                   /* composite_class */
  /* geometry_manager */           GeometryManager,
  /* change_managed */             ChangeManaged,
  /* insert_child */               XtInheritInsertChild,
  /* delete_child */               XtInheritDeleteChild,
  /* extension */                  NULL,
},

The following subsections detail each field from a Motif widget writer's perspective.

The geometry_manager Field

The geometry_manager method handles geometry requests from children of your manager widget. Your widget must specify one of the following for the geometry_manager field:

  • The name of your widget's geometry_manager method.

  • XtInheritGeometryManager to inherit the geometry_manager method of your widget's immediate superclass. The XmManager widget does not provide a geometry_manager method, so your widget cannot inherit this method from XmManager.

  • NULL, to indicate the absence of a geometry_manager method. Motif does not recommend this.

Most standard Motif manager widgets provide their own geometry_manager method. Motif makes no requirements of the geometry_manager method beyond those required by the Intrinsics.

The ExmGrid demonstration widget illustrates how to write one kind of geometry_manager method. You can find the source code for ExmGrid in demos/widgets/Exm/lib/Grid.c. (See Chapter 12 for an overview of geometry management in Motif.)

The change_managed Field

The Intrinsics call the change_managed method whenever:

  • A managed child becomes unmanaged.

  • An unmanaged child becomes managed.

Your widget must specify one of the following for the change_managed field:

  • The name of your widget's change_managed method.

  • XtInheritChangeManaged, to inherit the change_managed method of your widget's immediate superclass. The XmManager widget does not provide a change_managed method, so your widget cannot inherit this method from XmManager.

  • NULL, to indicate the absence of a change_managed method. Motif does not recommend this.

Motif requires that your change_managed method call the XmeNavigChangeManaged function. If your change_managed method does not, Motif's keyboard traversal will not work correctly.

The ExmGrid demonstration widget illustrates how to write one kind of change_managed method. You can find the source code for ExmGrid in demos/widgets/Exm/lib/Grid.c. (See Chapter 12 for an overview of geometry management in Motif.)

The insert_child Method

The Intrinsics call the insert_child method to report the creation of a new child under control of the manager widget.

You must set the insert_child method to one of the following:

  • XtInheritInsertChild, to inherit the insert_child method of your superclass. XmManager provides an insert_child method that your widget can inherit.

  • The name of your widget's insert_child method.

The insert_child method of XmManager simply calls the insert_child method of Composite. (See documentation on the Intrinsics for more information on Composite.)

If you do write your own insert_child method, Motif recommends that it call the insert_child method of XmManager. For example, suppose you are writing a manager widget that can only support one child. The following insert_child method rejects any attempt to add a second child. If the added child is the first child, then MyManagerInsertChild calls the insert_child method of XmManager.

MyManagerInsertChild(Widget child)
{
  ExmMyManagerWidget cb = (ExmMyManagerWidget) XtParent(child);
  if (cb->composite.num_children > 1)
    XmeWarning((Widget)cb, "MyManager cannot manage more than one child");
  else
/* Call the insert_child method of XmManager to update child info. */
    (*((XmManagerWidgetClass) xmManagerWidgetClass)
     ->composite_class.insert_child) (child);
}

The delete_child Method

The Intrinsics call the delete_child method to report the destruction of a child under control of the manager widget. The widget ID of the deleted child is the sole argument passed to the delete_child method.

You must set the delete_child method to one of the following:

  • XtInheritDeleteChild, to inherit the delete_child method of your superclass. XmManager provides a delete_child method that your widget can inherit.

  • The name of your widget's delete_child method.

The delete_child method of XmManager does the following:

  • Determines if the deleted child is the one stored in the manager.selected_gadget field. If it is, delete_child sets manager.selected_gadget to NULL. (See later in this chapter for more information on manager.selected_gadget.)

  • Determines if the deleted child is the one indicated by the XmNinitialFocus resource. If it is, delete_child sets XmNinitialFocus to NULL.

  • Determines if the deleted child is the one stored in the manager.active_child field. If it is, delete_child sets manager.active_child to NULL. (See later in this chapter for more information on manager.active_child.)

  • Finds the widget that is the tab group manager for the deleted child. If the tab group manager is not your manager widget, delete_child examines the tab group manager's manager.active_child field. If this field holds the widget ID of the deleted child, delete_child sets the tab group manager's manager.active_child field to NULL.

  • Calls the delete_child method of Composite.

The extension Field

The Composite class supports an extension record. The only nontrivial field in this extension record is called accepts_objects. If you specify the extension field as NULL, an extension record is automatically installed and accepts_objects is set to True. All but one of the standard Motif manager widgets (XmRowColumn) set the extension field to NULL.

If your manager widget requires that accepts_objects be False, then you must create an extension record with the accepts_objects field set to False. Furthermore, you must set the extension field to the name of your own composite class extension record.

The ConstraintClassPart Structure

The third part of the class record is the ConstraintClassPart structure. For example, following is theConstraintClassPart structure of the ExmGrid widget:

{                 /* constraint_class */
  /* resources */                  constraints,
  /* num_resources */              XtNumber(constraints),
  /* constraint_size */            sizeof(ExmGridConstraintRec),
  /* initialize */                 NULL,
  /* destroy */                    NULL,
  /* set_values */                 ConstraintSetValues,
  /* extension */                  NULL,
},

The following subsections detail each of these fields.

The resources (constraints) Field

The resources field holds the name of the constraints array. This array has the same syntax as a resources array. For example, following is the constraints array of the ExmGrid widget:

static XtResource constraints[] =
{
    {
        ExmNgridMarginWidthWithinCell,
        ExmCGridMarginWidthWithinCell,
        XmRHorizontalDimension,
        sizeof (Dimension),
        XtOffsetOf( ExmGridConstraintRec,
                   grid.grid_margin_width_within_cell),
        XmRImmediate,
        (XtPointer) 0
    },
    {
        ExmNgridMarginHeightWithinCell,
        ExmCGridMarginHeightWithinCell,
        XmRVerticalDimension,
        sizeof (Dimension),
        XtOffsetOf( ExmGridConstraintRec,
                   grid.grid_margin_height_within_cell),
        XmRImmediate,
        (XtPointer) 0
    },
};

Motif also supports synthetic constraints, which are explained later in this section.

The num_resources Field

The num_resources field holds the number of constraints defined by the array in the resources field of the ConstraintClassPart structure. If your widget does not provide a constraints array, then you should specify 0 for the num_resources field. If your widget does provide a constraints array, then your widget should use the XtNumber macro to count these resources. For example, the ExmSimple widget does provide a resources array, so its num_resources field looks as follows:

/* num_resources */                XtNumber(constraints),

The constraint_size Field

The constraint_size field holds the size of the full constraint structure. For example, the full constraint structure of the ExmGrid demonstration widget is named ExmGridConstraintRec; therefore, the Core class part of ExmSimple defines the constraint_size field as follows:

/* constraint_size */                sizeof(ExmGridConstraintRec);

The Constraint initialize Field (Chained)

To satisfy the Constraint initialize field, you can either specify the name of your widget's Constraint initialize method or you can specify NULL, to indicate the absence of a Constraint initialize method.

The Constraint initialize field is chained; therefore, the Intrinsics call the Constraint initialize method of XmManager before calling the Constraint initialize method in your own widget. The Constraint initialize method of XmManager examines each child of your widget as it is created. The response taken by this method depends on whether the created child is a widget or is a gadget.

If the created child is a gadget, the Constraint initialize method of XmManager examines the selected events of its gadgets. If the selected events are any of the following, the Constraint initialize method installs an event handler:

  • Motion

  • Enter

  • Leave

The event handler dispatches events to the appropriate gadget for analysis.

If the created child is a widget, the Constraint initialize method installs accelerators stored in the accelerator widget.

The Constraint destroy Field (Chained)

The Constraint destroy field holds the name of a method that is invoked when a widget is destroyed. You must specify one of the following:

  • The name of your widget's Constraint destroy method. Your widget should provide a Constraint destroy method if your widget's Constraint initialize method allocated any dynamic memory. The Constraint destroy method of your widget is responsible for deallocating this dynamic memory.

  • NULL, to indicate the absence of a Constraint destroy method. Your widget should probably specify NULL if your widget's Constraint initialize method did not allocate any dynamic memory.

The Constraint destroy method is chained in subclass-to-superclass order. Therefore, the Intrinsics will call the Constraint destroy method of XmManager after calling the Constraint destroy method in your own widget. The Constraint destroy method of XmManager conditionally removes the event handler that was put into place by the Constraint initialize method of XmManager. That is, the Constraint destroy method of XmManager determines whether the event handler is still needed. If it is not needed, Constraint destroy removes it. Otherwise, Constraint destroy keeps it.

The Constraint set_values Field (Chained)

To satisfy the Constraint set_values field, you must specify one of the following:

  • The name of your widget's Constraint set_values method

  • NULL, to indicate the absence of a Constraint set_values method

The Constraint set_values field is chained; therefore, the Constraint set_values method of XmManager will be called before any Constraint set_values method in your own widget. The Constraint set_values method of XmManager determines whether any changes to gadget children (for instance, a change in the gadget's selected events) make it necessary to install or remove the event handler.

The extension Field

If you want your widget to support a ConstraintClassPart extension record, set the extension field to the name of that extension record. If you do not want this extension record, set the field to NULL.

The one nontrivial field in the extension record is get_values_hook. Motif makes no recommendations on this field. (See the Intrinsics documentation for details.)

The ManagerClassPart Structure

The fourth part of the class record is the ManagerClassPart structure. For example, following is the ManagerClassPart structure of the ExmGrid widget:

{                   /* manager class */
  /* translations */               XtInheritTranslations,
  /* syn_resources */              syn_resources,
  /* num_syn_resources */          XtNumber(syn_resources),
  /* syn_constraint_resources */   syn_constraints,
  /* num_syn_constraint_resources */ XtNumber(syn_constraints),
  /* parent_process */             XmInheritParentProcess,
  /* extension */                  NULL,
},

The following subsections explain what a Motif widget writer should know about these fields.

The translations Field

The translations field defines the keyboard traversal translations for your manager widget. For this field, you must specify one of the following:

  • NULL, to indicate the absence of keyboard traversal translations.

  • XtInheritTranslations, to inherit the keyboard traversal translations of the widget's superclass, which is typically XmManager.

  • The name of your own keyboard traversal translations string.

The keyboard traversal translations for the XmManager widget are as follows:

<EnterWindow>:                          ManagerEnter()
<LeaveWindow>:                          ManagerLeave()
<FocusOut>:                        ManagerFocusOut()
<FocusIn>:                         ManagerFocusIn()
:<Key>osfBeginLine:          ManagerGadgetTraverseHome()
:<Key>osfUp:                    ManagerGadgetTraverseUp()
:<Key>osfDown:                          ManagerGadgetTraverseDown()
:<Key>osfLeft:                          ManagerGadgetTraverseLeft()
:<Key>osfRight:                      ManagerGadgetTraverseRight()
s ~m ~a <Key>Tab:               ManagerGadgetPrevTabGroup()
~m ~a <Key>Tab:                      ManagerGadgetNextTabGroup()

If you provide your own keyboard traversal translations string, Motif strongly recommends that the string contain all the keyboard traversal translations of XmManager.

The syn_resources Field

The syn_resources field holds the name of the array that defines the widget's synthetic resources. Synthetic resources provide a mechanism for translating widget resource values between different formats. (See Chapter 6 for information on synthetic resources.)

If you do not wish to define synthetic resources for your widget, set the value of this field to NULL.

The num_syn_resources Field

The num_syn_resources field holds the number of synthetic resources defined by the array in the syn_resources field. If your widget does not provide a syn_resources array, then you should specify 0 for the num_syn_resources field. If your widget does provide a syn_resources array, then your widget should use the XtNumber macro to count these resources.

The syn_constraint_resources field

Synthetic constraints are to constraints what synthetic resources are to resources. In short, synthetic constraints provide a mechanism for automatic conversion of constraints between an external format and an internal format. (See Chapter 6 for details on synthetic resources.)

You must specify one of the following for the syn_constraint_resources field:

  • The name of your widget's synthetic constraint resources array. This array must have a base data type of XmSyntheticResource.

  • NULL, to indicate the absence of any synthetic constraints.

For example, the ExmGrid widget defines two synthetic constraints in its synthetic constraint resources array as follows:

static XmSyntheticResource syn_constraints[] =
{
    {
        ExmNgridMarginWidthWithinCell, /* resource name */
        sizeof (Dimension),  /* data type of resource */
        XtOffsetOf( ExmGridConstraintRec,
                      grid.grid_margin_width_within_cell), /* offset */
        XmeFromHorizontalPixels, /* conversion routine */
        XmeToHorizontalPixels /* conversion routine */
    },
    {
        ExmNgridMarginHeightWithinCell,
        sizeof (Dimension),
        XtOffsetOf( ExmGridConstraintRec, grid.grid_margin_height_within_cell),
        XmeFromVerticalPixels,
        XmeToVerticalPixels
    },
};

XmeFromHorizontalPixels and XmeToHorizontalPixels are functions that convert a constraint resource value between pixels and real-world dimensions assuming a horizontal resolution. (See Chapter 6 for details.)

The num_syn_constraint_resources Field

The num_syn_constraint_resources field holds the number of synthetic constraints defined by the array in the syn_constraint_resources field. If your widget does not provide a syn_constraint_resources array, then you should specify 0 for the num_syn_constraint_resources field. If your widget does provide a syn_constraint_resources array, then your widget should use the XtNumber macro to count these constraints.

The parent_process Field

The parent_process method provides a mechanism for a child to pass an event up to its parent. Motif widgets use this mechanism to pass an osfActivate or an osfCancel event up to the first manager in the hierarchy that can process it. The osfActivate and osfCancel of all Motif primitive actions end up calling their parent's parent_process method.

Your manager widget must set the parent_process field to one of the following:

  • NULL, to indicate the absence of any parent_process method. Motif does not recommend doing this.

  • XmInheritParentProcess, to indicate that you are inheriting the parent_process method of your superclass. The XmManager widget provides a parent_process method that your subclass can inherit.

  • The name of your widget's parent_process method.

The parent_process method of XmManager passes the received event up to the parent of the manager that received it. If that manager widget also inherits the parent_process method of XmManager, then the event will be passed to its parent, and so on. This trail of passed events ends when either of the following happens:

  • The event reaches a manager widget that defines a parent_process method. This manager widget is responsible for processing the event.

  • The event is passed to a parent that is not a manager widget; for example, the parent might be a Shell. In this case, the received event will be discarded.

For example, consider the hierarchy shown in Figure 4-2. Assume that ManagerA inherits the parent_process method of XmManager, but ManagerB provides its own parent_process method. Suppose that PrimitiveA receives an osfActivate event. Since ManagerA is the parent of PrimitiveA, the osfActivate event is passed up to ManagerA. ManagerA cannot process the event, so ManagerA passes the event up to its parent, ManagerB. ManagerB processes the osfActivate event.

Figure 4-2. A Hierarchy for Exploring the parent_process Method

On the other hand, if ManagerB had been a Shell rather than a manager, then the osfActivate event would have been ignored.

Many manager widgets have no need to track the osfActivate and osfCancel events of their children. For such widgets, inheriting the parent_process method of XmManager is appropriate. However, DialogBox widgets do need to know when a child has received an osfActivate or osfCancel event in order to activate the default button or the cancel button.

If you write your own parent_process method, it must have the following prototype:

Boolean ParentProcess(
        Widget                  w,
        XmParentProcessData     data)

The second argument to the method must be a XmParentProcessData structure. This structure has the following definition:

typedef struct XmParentProcessData {
        int             process_type;
        XEvent          *event;
        int             action;
        String          *params;
        Cardinal        *num_params;
};


process_type 

Specifies XmINPUT_ACTION.

event 

Points to the XEvent that triggered the call.

action 

Specifies either XmPARENT_ACTIVATE for an activation event or XmPARENT_CANCEL for a cancel event.

params 

Points to the parameter string that gets passed to the action.

num_params 

Specifies the number of parameters passed in params.

Your parent_process method must return a Boolean value. Return True if the parent of your widget is a manager with a parent_process field set to something other than NULL. Otherwise, return False.

Your widget's parent_process method must do one of the following tasks:

  • Handle the received XmParentProcessData structure.

  • Pass the received XmParentProcessData structure to the parent_process method of your widget's parent (but only if your widget's parent is a manager widget).

The following code illustrates how to do the latter task:

XmManagerWidgetClass manClass;

  manClass = (XmManagerWidgetClass) widget->core.widget_class;
  if (XmIsManager(widget) && manClass->manager_class.parent_process)
    return( (*manClass->manager_class.parent_process)( widget, data));

  return( FALSE) ;

The extension Field

The XmManager widget provides an extension record. Motif recommends that you specify the extension field as NULL. If you do, Motif will automatically supply an appropriate extension field for your widget. If you do not specify the extension field as NULL, you must specify the name of the manager class extension record.

The Manager Class Extension Record

The XmManager widget provides an XmManagerClassExtRec extension record. However, most standard Motif manager widgets do not define one. Nevertheless, the following is an example of one hypothetical manager widget that does:

static XmManagerClassExtRec MyWidgetMgrClassExtRec = {
    /* next_extension */             NULL,
    /* record_type */                NULLQUARK,
    /* version */                    XmManagerClassExtVersion,
    /* record_size */                sizeof(XmManagerClassExtRec),
    /* traversal_children */         TraversalChildren,
    /* object_at_point */            XmInheritObjectAtPointProc
};

The following subsections detail this extension record.

The next_extension Field

Your widget should always set the next_extension field to NULL.

The record_type Field

Your widget should always set the record_type field to NULLQUARK.

The version Field

Your widget must always set the version field to XmManagerClassExtVersion.

The record_size Field

The record_size field holds the size of the manager class extension record. You should set it as follows:

/* record_size */                 sizeof(XmManagerClassExtRec),

The traversal_children Field

The traversal_children field holds the name of a method that defines the list of traversable children managed by your widget. Your widget must set the traversal_children field to one of the following:

  • The name of your widget's traversal_children method.

  • XmInheritTraversalChildrenProc, to indicate that you are inheriting the traversal_children method of your superclass. The XmManager widget does not provide a traversal_children method, so you cannot inherit from it.

  • NULL, to indicate the absence of a traversal_children method.

Most standard Motif manager widgets set this field to NULL. If your widget does this, then your widget will obey the same traversal rules that most other Motif manager widgets enforce. That is, Motif will view all the children in your widget's composite.children list as potential candidates for traversal. However, some of these candidates may not actually be traversable. For example, a Motif traversal routine will mark a child as nontraversable if the child's XmNtraversalOn resource is set to False. (See the Motif Programmer's Guide for details on traversal.)

The only reason to write your own traversal_children method is that you do not want all of your widget's children to be potential candidates for traversal. A traversal_children method must have the following prototype:

Boolean  TraversalChildren(
        Widget          w,
        Widget          **childList,
        Cardinal        *numChildren)


w 

Specifies the widget ID of your widget.

childList 

Returns a pointer to the list of potentially traversable children. The traversal_children method must dynamically allocate this list. The caller is responsible for deallocating it.

numChildren 

Returns a pointer to the number of potentially traversable children returned into childList.

Your traversal_children method must return a Boolean value. Returning False means that your widget did not allocate any dynamic memory to hold the childList. In this case, the callers (Motif traversal routines) assume that all the children in the widget's composite.children list are potential candidates for traversal. Returning True means that your widget did allocate dynamic memory to create childList. Therefore, the caller is responsible for deallocating (with XtFree) the returned childList.

In order to create childList, your traversal_children method will probably start with the default child list stored in composite.children. Your traversal_children method will then

  • Remove some of the children from this list

  • Add some children to this list

  • Keep the contents of the list the same, but rearrange their order

For example, the XmRowColumn widget provides a traversal_children method. This method begins by gathering the default child list stored in composite.children. The code that does this looks something like this:

XmRowColumnWidget  RCWid = (XmRowColumnWidget)w;
 *childList = (WidgetList) XtMalloc(sizeof(Widget) *
                               (RCWid->composite.num_children+1));

The method then adds the visible tear-off control widget to the beginning of the child list. (If XmRowColumn did not provide a traversal_children method, the tear-off control widget would not be part of the traversable children list.) The modified childList is returned to the calling Motif traversal routine, which treats it as the list of potentially traversable children.

In the preceding code, the traversal_children method called XtMalloc to allocate enough dynamic memory to store the default child list.

The object_at_point Field

The object_at_point field holds a method that returns the child most closely associated with a specified position within your manager widget. Motif calls the object_at_point method of your widget when an application specifies your widget as the first argument to the XmObjectAtPoint function. Your widget must set the object_at_point field to one of the following:

  • XmInheritObjectAtPointProc, to indicate that you are inheriting the object_at_point method of your superclass. The XmManager widget provides an object_at_point method, and your manager widget can inherit this method.

  • The name of your object_at_point method.

All standard Motif manager widgets except XmContainer inherit the object_at_point method of XmManager. The object_at_point method of XmManager uses the following rules to determine which child to return:

  • If one child intersects the specified coordinate pair, that child's widget ID is returned.

  • If more than one child intersects the specified coordinate pair, the visible child's widget ID is returned.

  • If no child intersects the specified coordinate pair, NULL is returned.

If you do write your own object_at_point method, it must have the same prototype as the XmObjectAtPoint routine, namely:

Widget ObjectAtPoint(
        Widget          w,
        Position        x,
        Position        y)

widget 

Specifies your manager widget.

x 

Specifies the x-coordinate about which the caller is seeking child information. The x-coordinate is specified in pixels, relative to the left side of your manager.

y 

Specifies the y-coordinate about which the caller is seeking child information. The y-coordinate is specified in pixels, relative to the top side of manager.

An object_at_point method must return the child most closely associated with the specified x,y coordinate pair. Each object_at_point method is free to define "most closely associated" as it pleases. For example, your own object_at_point method might return the child closest to x,y, while another object_at_point method might return the child that is closest to just the x-coordinate.

The Instance Data Members of XmManager

The XmManager widget maintains the values of its resources inside the manager structure. Each resource value is stored in a different field of manager. For example, the value of the XmNshadowThickness resource is stored in the manager.shadow_thickness field. Your manager widget can access any of these fields; for example:

/* Add 2 pixels to the current shadow thickness */
 my_manager->my_manager.shadow_thickness += 2;

In addition to all the resource values, the manager structure also holds several fields not tied to resources. Widget writers should become familiar with the fields shown in the following subsections.

The manager.accelerator_widget Field

The accelerator_widget field is declared as follows:

Widget        accelerator_widget;

The manager.accelerator_widget field holds the name of a widget whose accelerators will be automatically propagated to all new children of this manager.

Your own manager widget may modify this field.

Suppose your own manager widget contains accelerators to be installed on all its descendants. In this case, your manager's initialize method should set the manager.accelerator_widget field to the widget ID of your manager widget. Motif will install these accelerators in all the descendants of your manager widget. Furthermore, Motif will copy the value of the manager.accelerator_widget field in your widget to all manager children of your widget.

The manager.active_child Field

The active_child field is declared as follows:

Widget    active_child;

The manager.active_child field holds the widget ID of the gadget that has keyboard traversal focus. A value of NULL indicates that none of this manager's gadgets currently have keyboard traversal focus.

Your own manager widget should not modify the value of this field.

The manager.background_GC Field

The background_GC field is declared as follows:

GC        background_GC;

XmManager creates the starting GC, which is stored in the manager.background_GC field. Your widget cannot modify the fields in this GC; however, your widget can deallocate this GC and create a new GC more to your liking. The values in this GC are the default values generated by XtGetGC, except those noted in the following list:

  • The foreground is set to the value of the XmNbackgroundPixel resource of Core.

  • The background is set to the value of the XmNforeground resource of XmManager.

If the widget user specifies a valid pixmap for the XmNbackgroundPixmap resource of Core, then

  • The tile field is set to the value of the pixmap named by the XmNbackgroundPixmap resource.

  • The fill_style field is set to FillTiled.

On the other hand, a widget user might not specify a value for the XmNbackgroundPixmap resource, or might specify a bad value for the resource. In either case, the values of tile and fill_style are the defaults generated by XtGetGC.

The manager.bottom_shadow_GC Field

The bottom_shadow_GC field is declared as follows:

GC        bottom_shadow_GC;

XmManager creates the starting GC stored in the manager.bottom_shadow_GC field. Your widget cannot modify the fields in this GC; however, your widget can deallocate this GC and create a new GC more to your liking. The values in this GC are the default values generated by XtGetGC, except those noted in the following list:

  • The foreground is set to the value of the XmNbottomShadowColor resource of XmManager.

  • The background is set to the value of the XmNforeground resource of XmManager.

If the widget user specifies a valid pixmap for the XmNbottomShadowPixmap resource of XmManager, then

  • The tile field is set to the value of the pixmap named by the XmNbottomShadowPixmap resource.

  • The fill_style field is set to FillTiled.

On the other hand, a widget user might not specify a value for the XmNbottomShadowPixmap resource, or might specify a bad value for the resource. In either case, the values of tile and fill_style are the defaults generated by XtGetGC.

The manager.eligible_for_multi_button_event Field

The eligible_for_multi_button_event field is declared as follows:

XmGadget  eligible_for_multi_button_event;

Motif uses this field to implement multiclick events on gadgets.

Your widget should not alter the value in this field.

The manager.event_handler_added Field

The event_handler_added field is declared as follows:

Boolean   event_handler_added;

The event_handler_added field is a flag whose initial value is False. The initialize method in the ConstraintClassPart of XmManager sets this flag to True when it installs a gadget event handler.

Your own manager widget should not modify the value of this field.

The manager.has_focus Field

The has_focus field is declared as follows:

Boolean   has_focus;

XmManager sets this field to True when the manager widget has focus and sets this field to False when the manager widget does not. Note that, if a child widget has focus, then XmManager sets this field to False. However, if a child gadget has focus, then XmManager sets this field to True.

Your own manager widget should not modify the value of this field.

The manager.highlight_GC Field

The highlight_GC field is declared as follows:

GC        highlight_GC;

XmManager creates the starting GC, which is stored in the manager.highlight_GC field. Your widget can not modify the fields in this GC; however, your widget can deallocate this GC and create a new GC more to your liking.

The values in this GC are the default values generated by XtGetGC, except those noted in the following list:

  • The foreground is set to the value of the XmNhighlightColor resource of XmManager.

  • The background is set to the value of the XmNbackground resource of Core.

If the widget user specifies a valid pixmap for the XmNhighlightPixmap resource of XmManager, then

  • The tile field is set to the value of the pixmap named by the XmNhighlightPixmap resource.

  • The fill_style field is set to FillTiled.

On the other hand, a widget user might not specify a value for the XmNhighlightPixmap resource, or might specify a bad value for the resource. In either case, the values of tile and fill_style are the defaults generated by XtGetGC.

The manager.highlighted_widget Field

The highlighted_widget field is declared as follows:

Widget   highlighted_widget;

The highlight_widget fields holds the name of the gadget currently pointed to by the pointer (typically, a mouse). If the pointer does not point to a gadget, then the value of this field will be NULL.

Your own manager widget should not modify the value of this field.

The manager.keyboard_list Field

The keyboard_list field is declared as follows:

XmKeyboardData *keyboard_list;

Motif no longer uses this field.

The manager.num_keyboard_entries Field

The num_keyboard_entries field is declared as follows:

short     num_keyboard_entries;

Motif does not currently use this field.

The manager.selected_gadget Field

The selected_gadget field is declared as follows:

XmGadget  selected_gadget;

Motif initializes the selected_gadget field to NULL. When a user selects a gadget (typically, by pressing a mouse button), Motif arms the gadget and sets selected_gadget to the ID of the selected gadget. When the user releases the mouse button, Motif disarms the gadget and sets selected_gadget to NULL.

Your widget should not alter the value in this field.

The manager.size_keyboard_list Field

The size_keyboard_list field is declared as follows:

short     size_keyboard_list;

Motif does not currently use this field.

The manager.top_shadow_GC Field

The top_shadow_GC field is declared as follows:

GC        top_shadow_GC;

XmManager creates the starting GC stored in the top_shadow_GC field. Your widget can not modify the fields in this GC; however, your widget can deallocate this GC and create a new GC more to your liking.

The values in this GC are the default values generated by XtGetGC, except those noted in the following list:

  • The foreground is set to the value of the XmNtopShadowColor resource of XmManager.

  • The background is set to the value of the XmNforeground resource of XmManager.

If the widget user specifies a valid pixmap for the XmNtopShadowPixmap resource of XmManager, then

  • The tile field is set to the value of the pixmap named by the XmNtopShadowPixmap resource.

  • The fill_style field is set to FillTiled.

On the other hand, a widget user might not specify a value for the XmNtopShadowPixmap resource, or might specify a bad value for the resource. In either case, the values of tile and fill_style are the defaults generated by XtGetGC.