Callback routines are the heart of a Motif application. Many widget classes have resources whose values are lists of callback procedures. When the user acts on a widget--for example, pressing a PushButton--Motif invokes the callback routines in the corresponding callback list. If an application needs to take some action when the user presses a PushButton, it supplies a callback routine and adds that routine to the appropriate callback list.
Callbacks are not the only means Motif uses to notify an application of a user action. An application can also supply its own action routines and event handlers. The main difference between these kinds of procedures is the level of abstraction at which Motif or Xt invokes the procedures:
Most applications use only callback procedures. Action routines and event handlers are discussed in Chapter 13.
Each callback procedure is a function of type XtCallbackProc. The procedure takes three arguments: a widget and two pointers to data. The first pointer is to data that the application has told the widget to pass back to the application when the callback procedure is invoked. The second pointer is to data that the widget passes to all callbacks on the callback list. A callback procedure returns no value.
The application data argument is primarily for passing data that the application maintains separately from the widget itself. The widget data argument for most Motif widgets is a pointer to a structure containing information that varies by widget class. For example, when the user changes the value of a ToggleButton, Motif invokes callback procedures with a pointer to an XmToggleButtonCallbackStruct structure as the third argument. This structure has three members:
The documentation for each widget class in the Motif Programmer's Reference describes any callback structures that the widget passes to callback procedures as widget data. Note that a callback procedure can change the values of some members of these structures. Because the order of procedures in a callback list is unspecified, an application that uses multiple callback procedures in the same list must use caution in changing these values.
Following is a simple callback procedure that an application might use to set the state of a valve when the user changes the value of a ToggleButton. The application data passed in the callback in this example might be a pointer to a valve object associated with the ToggleButton:
void ToggleValueChangedCB(Widget toggle, XtPointer app_data, XtPointer widget_data) { Valve *valve_p = (Valve *) app_data; XmToggleButtonCallbackStruct *toggle_info = (XmToggleButtonCallbackStruct *) widget_data; ChangeValveState(*valve_p, ((Boolean) toggle_info->set == TRUE) ? VALVE_ON: VALVE_OFF); }
To register a callback procedure with a widget, an application uses XtAddCallback or XtAddCallbacks after declaring the callback procedure and creating the widget. The following code fragment creates a ToggleButton for each valve in a global list of valves:
... char name[20]; Widget toggles[N_VALVES]; int i; Valve *valve_p; for(i = 0, valve_p = valves; i < N_VALVES; i++, valve_p++) { sprintf(name, "valve_state_%d", i); toggles[i] = XmCreateToggleButton(parent, name, (ArgList) NULL, 0); XtAddCallback(toggles[i], XmNvalueChangedCallback, (XtCallbackProc) ToggleValueChangedCB, (XtPointer) valve_p); }
To remove a callback procedure from a callback list, use XtRemoveCallback or XtRemoveCallbacks. Because Motif sometimes adds its own callbacks to callback lists, do not use XtRemoveAllCallbacks to remove all callbacks from a list.