Процедуры обратного вызова являются сердцем Motif приложения. Многие классы виджетов имеют ресурсы чьим значением являются списки процедур обратного вызова. Когда пользователь действует на виджет, например, нажимает кнопку PushButton, Motif вызывает процедуры обратного вызова в соответствующем списке. Если приложению необходимо выполнить некоторые действия когда пользователь нажимает кнопку PushButton, оно предоставляет процедуру обратного вызова и добавляет ее в соответствующий список процедур обратного вызова.
Процедуры обратного вызова не единственное средство, которое использует Motif для оповещения приложения о действиях пользователя. Приложение может также поддерживать собственные процедуры действий и обработчики сообщений. Основным отличием между этими видами процедур является уровень абстракции на котором Motif и Xt вызывает процедуры:
Диспетчер событий Xt вызывает обработчик событий всякий раз когда событие некоторого типа возникает в указанном виджете.
Менеджер трансляции Xt вызывает процедуры действий когда последовательность событий совпадает со спецификацией событий в таблице трансляции виджета.
Motif виджет вызывает процедуры обратного вызова когда ввод пользователя означает действие которое выражает виджет, типа активации кнопки PushButton. Очень часто виджет вызывает процедуры обратного вызова из процедур действий. Необязательно только одно действие может вызвать один и тот-же список процедур обратного вызова.
Многие Motif приложения используют только процедуры обратного вызова. Процедуры действий и обработчики событий описываются в главе 13.
Каждая процедура обратного вызова является функцией типа XtCallbackProc. Процедуры принимают три аргумента: виджет и два указателя на данные. Превый указатель является данными которые приложение указало виджету передавать обратно приложению когда вызывается процедура обратного вызова. Второй указатель используется для передачи виджетом данных всем процедурам в списке. Процедуры обратного вызова не возвращают значения.
Аргумент данных приложения предназначен в первую очередь для передачи данных, которые приложение поддерживает отдельно от самого виджета. Аргумент данных виджета для большинства Motif виджетов является указателем на структуру, содержащую которая зависит от класса виджета. Например, когда пользователь изменяет значение кнопки ToggleButton, Motif вызывает процедуры обратного вызова с указателем на структуру типа XmToggleButtonCallbackStruct в качестве третьего аргумента. Эта структура содержит три поля:
Целое число обозначающее причину вызова процедуры обратного вызова. Когда пользователь изменил значение причина будет \const{XmCR_VALUE_CHANGED}. Обычно причины обозначаются именами, начинающимися с символов bold{XmCR}.
Указатель типа XEvent на событие которое послужило причиной вызова процедуры.
Целое число которое обозначает новое состояние кнопки ToggleButton, т.е. выбрана или не выбрана.
Документация на каждый виджет в Motif. Справочник программиста описывает все структуры, которые виджет передает процедурам обратного вызова как данные виджета. Имейте в виду, что процедуры обратного вызова могут изменить значения некоторых полей этих структур. Поскольку порядок вызова процедур в списке процедур обратного вызова не определена, приложение которое использует несколько процедур обратного вызова в одном списке должно соблюдать осторожность при изменении этих значений.
Ниже приводится простейшая процедура обратного вызова, которую приложение использует для изменения состояния клапана когда пользователь изменяет значение кнопки ToggleButton. Данные приложения передаваемые процедуре в этом примере должны быть указателем на объект кланана связянного с кнопкой 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); } |
Для регистрации процедуры обратного вызова у виджета, приложение использует XtAddCallback или XtAddCallbacks после определения процедуры обратного вызова и создания виджета. Следующий фрагмент кода создает кнопку ToggleButton для каждого клапана из глобального списка клапанов:
... 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); } |
Для удаления процедур обратного вызова из списков процедур обратного вызова исползуются XtRemoveCallback или XtRemoveCallbacks. Поскольку Motif иногда добавляет списки процедур обратного вызова собственные процедуры, не исльзуйте XtRemoveAllCallbacks для удаления всех процедур из списка.