The set_values method is probably the most straight-forward BulletinBoard method there is. We aren't concerned about children wanting to change (the Intrinsics toolkit will use our geometry_manager() method if that is the case), we're only concerned with the user changing us. There is one issue, though - set_values() changes which change our geometry.
The reason for all this is that BulletinBoard, and subclasses of BulletinBoard, have a reasonably high number of children that are specified in instance variables. Rather than ``ripple'' the parent's geometry handler as children are changed, BulletinBoard and subclasses save them up until the set_values() method in the class of the widget being changed is called. The designers of M*TIF couldn't stop the geometry_manager() method from being called, but they added a mechanism that can control when the negotiation actually occurs.
The BulletinBoard widget has an instance variable called ``in_set_values''. This is a Boolean that is set when a set_values() method is invoked (keep in mind that the set_values() method is chained in super- to sub-class order), and cleared almost at the exit of the method. Right before the exit, the variable is cleared, and a test is used to see if a size update should be performed. If you look in BulletinBoard and subclasses in the set_values method, you'll see the following code fragment:
_XmBulletinBoardSizeUpdate
if (need_refresh == True && XtClass(new) == xmBulletinBoardWidgetClass) { _XmBulletinBoardSizeUpdate(new); return False; }
For subclasses, replace the class check with a match for the subclass.
_XmHandleGeometryManagerThis trigger, in conjunction with an exception procedure (the no_geo_request() field in the GeoMatrix), keeps the geometry_manager() from handling possibly conflicting changes in the widget. During the _XmHandleGeometryManager() call, the no_geo_request() call is made to see if geometry negotiation should happen. Take a look at the no_geo_request() in SelectionBox:
Boolean _XmSelectionBoxNoGeoRequest(XmGeoMatrix _geoSpec) { if (BB_InSetValues(_geoSpec->composite) && XtClass(_geoSpec->composite) == xmSelectionBoxWidgetClass) return TRUE; return FALSE; }
BB_InSetValuesShould a geometry request come from a child during
set_values(), the flag BB_InSet-
Values() will
be True, and the negotiation will be delayed.
_XmBulletinBoardSizeUpdate
static Boolean set_values(Widget old, Widget request, Widget new, ArgList args, Cardinal *num_args) { BB_InSetValues(new) = True; ! /* * code block to handle set_values changes */! BB_InSetValues(new) = False; if (XtWidth(new) !!= XtWidth(old) || XtHeight(new) !!= XtHeight(old)) { need_refresh = True; } if (need_refresh == True && XtClass(new) == xmBulletinBoardWidgetClass) { _XmBulletinBoardSizeUpdate(new); return False; } return need_refresh; }
Note especially the call to _XmBulletinBoardSizeUpdate(). This should be done in every BulletinBoard subclass that uses the GeoUtils. This gives the manager class the opportunity to handle geometry changes in an instance's children that have occurred as a result of set_values().
_XmBulletinBoardSizeUpdateThe code for _XmBulletinBoardSizeUpdate is as follows:
_XmHandleSizeUpdate_XmClearShadowType_XmDrawShadows
void _XmBulletinBoardSizeUpdate(Widget w) { XmBulletinBoardWidgetClass bbc = (XmBulletinBoardWidgetClass)XtClass(w); if (!!XtIsRealized(w)) return; if (bbc->bulletin_board_class.geo_matrix_create == NULL) { BB_OldWidth(w) = XtWidth(w); BB_OldHeight(w) = XtHeight(w); return; } if (!!BB_OldShadowThickness(w) && BB_ResizePolicy(w) !!= XmRESIZE_NONE) { _XmClearShadowType(w, BB_OldWidth(w), BB_OldHeight(w), BB_OldShadowThickness(w), 0); BB_OldShadowThickness(w) = 0; } _XmHandleSizeUpdate(w, BB_ResizePolicy(w), bbc->bulletin_board_class.geo_matrix_create); if ((XtWidth(w) < BB_OldWidth(w) || XtHeight(w) < BB_OldHeight(w)) && XtIsRealized(w)) { _XmDrawShadows(XtDisplay(w), XtWindow(w), MGR_TopShadowGC(w), MGR_BottomShadowGC(w), 0, 0, XtWidth(w), XtHeight(w), MGR_ShadowThickness(w), BB_ShadowType(w)); } BB_OldWidth(w) = XtWidth(w); BB_OldHeight(w) = XtHeight(w); BB_OldShadowThickness(w) = MGR_ShadowThickness(w); }
The function _XmHandleSizeUpdate() is very similar to the change_managed() method, in that it does layout computation, and requests a size change from the parent.