3.3.4. Управление очередью событий.

    Как уже отмечалось выше в 3.1.3., каждое приложение вызывает процедуру XtAppMainLoop( ) или XtMainLoop( ) для организации процесса получения и рассылки событий. Данные процедуры, в свою очередь, вызывают две процедуры XtAppNextEvent( ) (XtNextEvent( )) и XtDispatchEvent( ). Другими словами работа XtAppMainLoop( ) эквивалентна следующей последовательности операторов:

. . . . . . .
XtAppContext prAppContext
. . . . . . .
for ( ; ; )  {
    XEvent rEvent;
    XtAppNextEvent (prAppContext, &rEvent);
    XtDispatchEvent (&rEvent);
}
. . . . . . .

    Процедура XtAppNextEvent( ) имеет прототип:

void XtAppNextEvent (XtAppContext prAppContext,
                     XEvent *prEvent);

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

    Работает XtAppNextEvent( ) так: если в очереди первым идет событие о готовности данных в файле (внешнем устройстве), или там находится событие, инициирующее вызов соответствующей таймер-процедуры, то вызывается процедура (процедуры), зарегистрированные с помощью процедур XtAppAddInput( ) (XtAddInput( )) или XtAppAddTimeOut( ) (XtAddTimeOut( )). Если никаких событий в очереди нет, то вызываются work-процедуры, зарегистрированные процедурой XtAppAddWorkProc( ). Если же в очереди есть событие от сервера, то XtAppNextEvent( ) удаляет его из очереди и переносит в структуру, на которую указывает ее второй аргумент.

    Процедура XtDispatchEvent( ) имеет прототип:

void XtDispatchEvent (XEvent *prEvent); 

    Она анализирует событие и вызывает соответствующую callback-процедуру, action-процедуру или обработчик событий. Если таковых нет, то событие игнорируется. Если для события зарегистрировано несколько event handler или action-процедур, то порядок их выполнения не определен.

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

void MyMainLoop (XtAppContext prAppContext)
{
    XEvent prEvent;
    . . . . . . .
    for ( ; ; )
    {
        XtAppNextEvent (prAppContext, &prEvent);
        . . . . . . .
    /* Предобработка события */
    . . . . . . .
    XtDispatchEvent (&prEvent);
    . . . . . . .
    /* Постобработка события */
    . . . . . . .
    }
}

    Xt предусматривает целый набор процедур для работы с очередью событий. Например, функция XtAppPeekEvent( ) позволяет получить информацию о следующем событии без удаления его из очереди. Процедура имеет следующий прототип:

Boolean XtAppPeekEvent (XtAppContext prAppContext,
                        XEvent  *prEvent);

    Здесь prAppContext - это контекст приложения; второй аргумент используется для хранения информации о следующем событии в очереди. Функция возвращает True, если событие в очереди есть X событие, в противном случае (т.е., если это событие, инициирующее вызов соответствующей таймер-процедуры, или какое-либо другое событие) возвращается False. Событие из очереди не удаляется.

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

void XtAppProcessEvent (XtAppContext prAppContext,
                        XtInputMask nMask);

    Здесь первый аргумент задает контекст приложения. Второй аргумент определяет маску событий, при этом последняя может состоять из одной или нескольких констант, разделенных оператором OR ( | ). Указанные константы следующие:

XtIMXEvent - X событие
XtIMTimer - событие, инициирующее вызов таймер-процедуры
XtIMAlternateInput - событие о готовности данных
XtIMAll - все события.

    Аналогичные описанным выше процедурам функции XtPeekEvent( ) и XtProcessEvent( ) отличаются только отсутствием аргумента prAppContext. Более подробную информацию о приведенных и других функциях, позволяющих работать с событиями в очереди, можно найти например в [9, 10].