Main Page
Статьи Компоненты Ссылки Разное

Сообщения X-Window в Kylix-приложениях

Андрей Боровский, kylixportal@narod.ru, 23/03/03

Прежде всего уточним терминологию. Структуры, о которых пойдет речь в этой статье, в оригинальной документации по X-Window называются событиями (events). Мы будем называть эти структуры сообщениями, во-первых для того, чтобы не создавать путаницы с событиями Kylix, а во-вторых, потому, что события X-Window во многом (хотя и не во всем) напоминают сообщения ОС Windows.

Сообщения ОС Windows предоставляют программисту одно существенное удобство: возможность выполнения некоторых действий, связанных с данной процедурой, после завершения этой процедуры. Ситуации, в которых подобный «разрыв» необходим, возникают довольно часто. В ОС Windows эта проблема решается следующим образом: перед завершением своей работы процедура посылает окну приложения сообщение, определенное пользователем. Обработчик этого события выполняет дальнейшие операции. Таким образом создается своеобразная «эстафета» из процедур. Реализации такого подхода при программировании в Kylix связана с определенными сложностями. Конечно, указанную задачу можно решить в Kylix с помощью потоков, однако такое решение потребует создания потоковых объектов. Другое решение связано с использованием сообщений графической системы X-Window.

Вдаваться в подробности реализации механизма сообщений X-Window мы здесь не будем. Рассмотрим, как этот механизм можно использовать практически при программировании в Kylix.

Визуальные компоненты Kylix основаны на библиотеке Qt library. Вся обработка сообщений системы X-Window осуществляется классами Qt library, так что обычно при программировании в Kylix нам не приходится иметь дело с сообщениями X-Window. Тем не менее, Kylix предоставляет нам возможность работать с этими сообщениями. Для того, чтобы обрабатывать сообщения системы X-Window, в Kylix реализован фильтр сообщений.

Фильтр сообщений X-Window представляет собой функцию, которая получает каждое сообщение, адресованное данному приложению X-Window. Функция может обрабатывать полученное сообщение самостоятельно, передать его для обработки приложению или заблокировать его. Объявление функции-фильтра выглядит так:

function X11EventFilterFunc(XEvent: PXEvent): Boolean; cdecl;

Отметим, что функция-фильтр должна быть именно самостоятельной функцией, а не методом класса. Аргументом функции является указатель на структуру XEvent, определенную в модуле Xlib. От значения, возвращенного функцией, зависит, будет ли приложение выполнять дальнейшую обработку сообщения или нет. Если функция возвращает значение True, дальнейшая обработка сообщения выполняться не будет. По этой причине функция по умолчанию должна возвращать значение False.

Для того, чтобы установить функцию-фильтр сообщений X-Window, следует вызвать метод-функцию SetX11EventFilter объекта Application. Аргументом этого метода является процедурная переменная или функция-фильтр. Значение, возвращаемое методом SetX11EventFilter, представляет собой ссылку на ранее установленный фильтр (если таковой имеется). Благодаря этому несколько фильтров можно вызвать по цепочке. Следует особо отметить, что фильтр сообщений X-Window будет перехватывать все сообщения, адресованные данному X-приложению, независимо от того, с каким окном эти сообщения связаны (в системе X-Window приложение может получать сообщения, связанные с окнами, владельцем которых оно не является).

В отличие от ОС Windows сообщения (события) X-Window являются сложными структурами данных. В системе существует ряд стандартных сообщений, а существующая в Windows концепция сообщений, определенных пользователем, в X-Window отсутствует. Как же в таком случае послать окну программы произвольное сообщение?

В этом нам поможет реализованный в X-Window механизм свойств окон. Свойства, это данные, добавляемые к структуре окна. Некоторые свойства являются стандартными для системы X-Window, например свойства, определяющие размеры и положение окна. Для нас сейчас важно то, что программист, создающий приложения X-Window может вводить собственные свойства для окон. Каждое свойство имеет уникальный идентификатор (подробнее об этом будет сказано ниже). В ответ на вызов функции, манипулирующей свойствами, приложение, вызвавшее функцию, получает сообщение PropertyNotifyEvent, которое содержит идентификатор того свойства, для которого вызывалась функция. Таким образом, для отправки собственного сообщения приложению мы должны выполнить следующие действия:

Выше мы говорили об идентификаторе свойства. Свойства окон идентифицируются именами, которые представляют собой строки символов. Однако функции для работы со свойствами используют не строки, а атомы. Атомы – это численные идентификаторы, соответствующие строковым именам объектов X-Window (в модуле XLib определен специальный тип TAtom).

Атомы для стандартных имен определены в заголовочных файлах X-Window и модуле XLib. Создать атом для произвольного имени можно при помощи функции XInternAtom. Эта функция создает пару имя/атом, ничего не зная о том, как будут использоваться эти объекты, по этому ее можно вызвать в самом начале программы, например в разделе initialization. Создание нового атома свойства может выглядеть следующим образом:


var
  MyProperty : TAtom;
...
initialization

  MyProperty := XInternAtom(Application.Display, 'MY_PROPERTY', XFALSE);

Теперь для отправки сообщения мы можем использовать функцию XChangeProperty. Общий прототип метода объекта, посылающего перед своим завершением сообщение приложению, может выглядеть так:


procedure TForm1.Method(Sender: TObject);
var
  Data : Integer;
begin
  ...
  XChangeProperty(Application.Display, QWidget_winId(Handle), MyProperty, 
    XA_INTEGER, 32, PropModeReplace, @Data, 1);
end;

Первый параметр функции XChangeProperty – указатель на дисплей, с помощью которого процесс осуществляет связь с системой X-Window. Вторым параметром является идентификатор окна, свойствами которого мы собираемся манипулировать. Получить идентификатор окна главной формы приложения можно с помощью функции QWidget_winId, передав ей в качестве параметра свойство Handle формы. Далее следует имя свойства, идентифицируемое атомом MyProperty. Аргумент PropModeReplace указывает функции, что нужно заменить текущее значение данного свойство (если на момент вызова функции такого свойства не существует, оно будет создано). Остальные параметры функции XChangeProperty указывают тип и структуру данных свойства. Свойства окон могут быть данными самых разных типов и размеров. Поскольку в данном случае само свойство нас не интересует, мы используем самый простой тип – Integer.

После вызова функции XChangeProperty процесс, вызвавший функцию получит сообщение PropertyNotifyEvent, в одном из полей которого будет храниться атом MyProperty. Таким образом мы сможем отличить это сообщение от всех остальных. В этом случае функция-фильтр сообщений может иметь следующий вид:


function X11EventFilterFunc(Event : PXEvent) : Boolean; cdecl;
begin
  Result := False;
  if Event.xtype = PropertyNotify then // Тип сообщения - PropertyNotifyEvent
  if Event.xproperty.atom = MyProperty then  // «Наше» сообщение
  begin
    ...
    Result := True; // Дальнейшая обработка сообщения не нужна
  end;
end;

Механизм работы с сообщениями демонстрирует прилагаемый пример.


Статья и примеры программ © 2003 Андрей Наумович Боровский. Воспроизведение возможно только с разрешения автора.

Используются технологии uCoz