Когда пользователь нажимает на кнопку мыши или клавишу клавиатуры, или когда окно программы нуждается в перерисовке, или когда происходят другие изменения в системе, сервер подготавливает соответствующий пакет данных и отправляет его той или иной программе (или программам). Этот пакет данных называется событием.
Типичная GUI программа имеет следующую структуру:
Возможных событий достаточно много; их список можно найти в файле X.pp
. Каждое из них имеет свой тип и соответствующую структуру данных. Все они вместе, как было сказано выше, описываются объединением XEvent
.
Как мы видели из примера в предыдущем пункте, программа для каждого из своих окон может выбрать события, которые будут ему передаваться. Делается это с помощью функции XSelectInput()
. При вызове этой процедуры требуемые события идентифицируются соответствующими флагами. Так событию, ButtonPress
(нажатие кнопки мыши) соответствует флаг ButtonPressMask
. Когда кнопка отпускается, сервер порождает событие ButtonRelease
, которому соответствует флаг - ButtonReleaseMask
.
Маска выбираемых событий может составляться с помощью побитового «ИЛИ» из таких значений:
KeyPressMask
- ожидать событие нажатия клавишиKeyReleaseMask
- ожидать событие отпускания клавишиButtonPressMask
- ожидать событие нажатия кнопки мышиButtonReleaseMask
- ожидать событие отпускания кнопки мышиEnterWindowMask
- ожидать событие входа в окноLeaveWindowMask
- ожидать событие выхода из окнаPointerMotionMask
- ожидать событие движения мышиного курсораPointerMotionHintMask
- ожидать событие движения мышиного курсора с дополнительными указаниямиButton1MotionMask
- ожидать событие движения мышиного курсора при нажатой первой кнопкеButton2MotionMask
- ожидать событие движения мышиного курсора при нажатой второй кнопкеButton3MotionMask
- ожидать событие движения мышиного курсора при нажатой третьей кнопкеButtonMotionMask
- ожидать событие движения мышиного курсора при любой нажатой кнопкеExposureMask
- ожидать событие необходимости перерисовки окнаVisibilityChangeMask
- ожидать событие изменения видимостиResizeRedirectMask
- ожидать событие изменения размеров окнаFocusChangeMask
- ожидать событие изменения фокуса вводаMappingNotify
- посылается, когда изменяется состояние клавиатуры (соответствие физических и логических кодов;ClientMessage
- так идентифицируются события, посылаемые от клиента к клиенту с помощью процедуры XSendEvent()
;SelectionClear
, SelectionNotify
, SelectionRequest
- эти события используются в стандартном механизме общения между программами, работающими в X;Expose
, NoExpose
- эти события могут посылаться, когда клиент пытается копировать содержимое одного окна в другое.
Частой ошибкой начинающих программистов является добавление кода для обработки нового события без добавления маски для этого события в XSelectInput()
. Можно часам сидеть и отлаживать программу в недоумении, почему она не реагирует на отпускание кнопки, только из-за того, что для кнопок событие нажатия зарегистрировано, а событие отпускания - нет.
Программа получает события в своем основном цикле. Для этого можно использовать ряд процедур. Наиболее простая из них -
Function XNextEvent(prDisplay : PDisplay; prEvent : PXEvent) : longint; cdecl; external;
Она «вынимает» из очереди событие, находящееся в ее «голове», сохраняет информацию о нем в переменной, на которую указывает параметр prEvent
, и возвращается. При этом само событие удаляется из очереди. Функция XPeekEvent()
также возвращает переданное сервером событие, но не удаляет его из очереди.
Процедура XPending()
возвращает общее число событий в очереди программы.
Итак, если событие выбрано для окна, то оно будет передано ему на обработку. А если нет? В этом случае событие передается родителю окна. Если и тот не желает обращать внимание на данное событие, то оно отправляется дальше, вверх по иерархии окон, и так до тех пор, пока либо не будет найдено окно, выбравшее это событие, либо событие не потеряется.
Задача может влиять на этот процесс продвижения события по иерархии окон. Если программа включает флаг, соответствующий событию, в специальный атрибут окна, то оно, достигнув это окно, не будет передано родителю, а будет тут же «снято с повестки дня». Этот атрибут - do_not_propagate
.