3.2.5.3. Обработчики событий.

    В Xt предусмотрен еще один механизм использования процедур для выполнения определенных действий при наступлении тех или иных событий. Это механизм обработчиков событий (event handler). Он позволяет определять отдельное событие (или их группу), при наступлении которого будет вызвана указанная программой процедура-обработчик. Обработчики событий менее гибки, чем action-процедуры, но зато значительно быстрее. Последнее происходит потому, что при вызове event handler не требуется поиск процедур по соответствующим "таблицам". В этом пункте будут рассмотрены отдельные аспекты работы с event handler.

    Для того чтобы программа могла использовать данную процедуру как обработчик событий, ее необходимо зарегистрировать специальным образом. Делается это с помощью процедуры XtAddEventHandler( ) или XtInsertEventHandler( ). Первая из них имеет следующий прототип:

void XtAddEventHandler (Widget prWidget,
	EventMask nEventMask, Boolean nNonMaskable,
	XtEventHandler pHandler, XtPointer pUserData);

    Здесь prWidget - идентифицирует объект, к которому будет добавлена процедура- обработчик pHandler. nEventMask - комбинация флагов, задающая события, в ответ на которые будет вызываться регистрируемая процедура (события и соответствующие им флаги приведены в приложении 1)Ссылка. Третий аргумент в процедуре XtAddEventHandler( ) - это логическая переменная равная True, если обработчик будет вызываться для событий, которые всегда посылаются программе. Это MappingNotify, ClientMessage, SelectionClear, SelectionNotify, SelectionRequest (заметим, что последние три события связаны с механизмом общения между программами через системный буфер (clipboard), описание которого выходит за рамки настоящего издания). Наконец, последний аргумент процедуры - pUserData - это указатель на данные, передаваемые в обработчик при его вызове. Если таковых нет, то аргумент должен быть равен NULL.

    Заметим, что для одного и того же события в списке обработчиков может быть зарегистрировано несколько функций. XtAddEventHandler( ) добавляет функцию pHandler в конец этого списка.

    Процедура, используемая как обработчик событий, должна иметь следующий прототип:

void HandlerProc (Widget prWidget, XtPointer pUserData,
	          XEvent  *prEvent, Boolean *pnContinue);

    Здесь первый аргумент указывает на объект, для которого заказана реакция на событие. Второй аргумент указывает на данные, передаваемые в обработчик из программы. Он равен аргументу pUserData, задаваемому при вызове функции XtAddEventHandler( ). Третий аргумент - указатель на событие, инициировавшее обращение к event handler. И, наконец, последний аргумент указывает, следует ли системе вызывать следующие зарегистрированные для данного события обработчики или нет. Перед вызовом процедуры система делает этот параметр равным True. Если программа не желает, чтобы событие обрабатывалось дальше, значение переменной, на которую указывает pnContinue, должно быть изменено на False.

    Функция XtInsertEventHandler( ) также заносит процедуру в список обработчиков того или иного события, но она позволяет поместить ее в произвольное место списка.

    XtInsertEventHandler( ) имеет следующий прототип:

void XtInsertEventHandler (Widget prWidget,
        EventMask nEventMask, Boolean nNonMaskable,
        XtEventHandler pHandler, XtPointer pUserData,
        XtListPosition nPosition);

    Первые пять аргументов полностью идентичны описанным выше для процедуры XtAddEventHandler( ). Последний аргумент - указывает, в какое место списка обработчиков будет помещена функция pHandler. Аргумент может принимать одно из двух предопределенных значений: XtListHead, которое означает, что функция будет помещена в "голову" списка и, следовательно, будет вызываться раньше любого event handler, зарегистрированного для данного объекта и события. Второе значение - XtListTail, которое указывает, что функция будет помещена в конец списка и будет вызываться после всех зарегистрированных процедур.

    Как мы упоминали ранее, для одного и того же события можно зарегистрировать несколько event handler, но при этом каждая функция с одинаковыми параметрами pUserData может встретиться в списке только один раз. Однако, если та же самая функция регистрируется с помощью XtInsertEventHandler( ), то она будет добавлена в список, но передвинута либо в конец списка либо в его начало.

    Вызов процедур XtAddEventHandler( ) и XtInsertEventHandler( ) может осуществляться до и после реализации соответствующего widget.

    Ниже приводится фрагмент кода, в котором с помощью функции XtAddEventHandler( ) регистрируется функция-обработчик, которая будет вызываться при изменении фокуса ввода для данного widget. Ее можно использовать для выполнения определенных действий при наступлении соответствующих событий.

. . . . . . .
void CheckFocus (Widget prWidget, XtPointer pUserData,
	XEvent  *prEvent)
{
   . . . . . . . .
   if (event->type == FocusIn)
   {
       /* Выполняются действия при получении фокуса ввода */
       . . . . . . .
   }
   else
   {
       /* Выполняются действия при потере фокуса ввода */
        . . . . . . 
   }
}
. . . . . . . .
main (int argc, char  *argv)
{
    . . . . . . . .
    XtAddEventHandler (prCoreWidget, FocusChangeMask, False,
		           (XtEventHandler) CheckFocus, NULL);
    . . . . . . . .
}

    Когда процедура-обработчик становится не нужной, ее можно удалить из списка. Для этого можно использовать процедуру

void XtRemoveEventHandler (Widget prWidget,
	EventMask nEventMask, Boolean nNonMaskable,
	XtEventHandler pHandler, XtPointer pUserData);

    Она имеет те же самые аргументы, что и процедура XtAddEventHandler( ). Если параметры в вызовах этих процедур не совпадают, то удаления указанного обработчика не произойдет. Так происходит, например, если параметр pUserData при вызове XtRemoveEventHandler( ) не совпадает с заданным при обращении к XtAddEventHandler( ).