====== Программирование в X-Window средствами Free Pascal ======
[[index|Перейти к содержанию]]
===== 1.5.2. Общение с менеджером окон =====
Менеджер окон - это специальный клиент, в задачи которого входит
интерактивное перемещение окон по экрану, изменение их размеров,
минимизация (превращение в пиктограмму) и многое другое.
Чтобы облегчить менеджеру его нелегкую жизнь, программам рекомендуется
при инициализации сообщить о себе определенную информацию.
Передается она через предопределенные свойства,
которые известны менеджеру и могут быть им прочитаны.
Некоторые из свойств (так называемые стандартные) задавать обязательно.
Все остальное определяется по усмотрению программы.
Наиболее простой способ задать стандартные свойства - обратиться
к процедурам ''XSetStandardProperties()''
или ''XSetWMProperties()''.
Ниже перечисляются свойства, создаваемые для менеджера окон программами,
а также процедуры для работы с ними.
* Имя (заголовок) окна. Идентифицируется атомом ''XA_WM_NAME'' и имеет тип "''TEXT''". Данные свойства - структура ''TXTextProperty''. Для задания свойства используется процедура ''XStoreName()'' (''XSetWMName()''). Получить его можно с помощью ''XFetchName()'' (''XGetWMName()'').
* Имя пиктограммы. Идентифицируется атомом ''XA_WM_ICONNAME'' и имеет тип "''TEXT''". Данные свойства - структура ''TXTextProperty''. Для задания свойства используется процедура ''XSetIconName()'' (''XSetWMIconName()''). Получить его можно с помощью ''XGetIconName()'' (''XGetWMIconName()'').
* Рекомендации (hints) о геометрии окна. Идентифицируется атомом ''XA_WM_NORMAL_HINTS'' и имеет тип ''XA_WM_SIZE_HINTS''. Данные свойства - структура типа ''TXSizeHints''. Для задания свойства используется процедура ''XSetNormalHints()''.
В ряде случаев стоит сообщить оконному менеджеру о том, какой размер окна мы хотим получить, и в каких пределах будут изменяться его размеры. Например, для терминальной программы (такой, как ''xterm''), хотелось бы, чтобы окно всегда содержало полное количество строк и столбцов. В других случаях нежелательно давать возможность менять размер окна (например, в диалоговых окнах). Эти пожелания можно передать оконному менеджеру, хотя ничто не помешает ему их проигнорировать.\\
Для этого необходимо создать структуру данных, заполнить ее необходимыми
данными и затем использовать функцию ''XSetWMNormalHints()'':
(* указатель на структуру рекомендаций о размерах. *)
var
win_size_hints : PXSizeHints;
win_size_hints := XAllocSizeHints();
if (win_size_hints=nil) then begin
writeln('XAllocSizeHints - нет памяти');
halt(1);
end;
(* Инициализация структуры *)
(* Вначале укажем, что передаются пожелания о размерах: *)
(* установим минимальный и начальный размеры. *)
win_size_hints^.flags := PSize OR PMinSize;
(* Затем указываем требуемые границы. *)
(* в нашем случае - создаем окно минимальным размером 300x200 *)
(* пикселей и устанавливаем начальный размер в 400x250. *)
win_size_hints^.min_width := 300;
win_size_hints^.min_height := 200;
win_size_hints^.base_width := 400;
win_size_hints^.base_height := 250;
(* Передаем пожелания о размерах оконному менеджеру. *)
XSetWMNormalHints(display, win, win_size_hints);
(* В конце необходимо освободить память из-под структуры. *)
XFree(win_size_hints);
Дополнительные параметры окна: способ работы с клавиатурой,
вид и положение пиктограммы. Идентифицируется атомом
''XA_WM_HINTS'' и имеет тип ''XA_WM_HINTS''.\\
Данные свойства - структура типа ''TXWMHints''.
Для задания свойства используется процедура ''XSetWMHints()''.
Структура типа ''XWMHints'', передаваемая функции
''XSetWMHints()'', должна быть подготовлена с помощью
''XAllocWMHints()'':
var
win_hints : PXWMHints;
icon_pixmap : TPixmap;
const
icon_bitmap_width=20;
icon_bitmap_height=20;
(* Определим битовое изображение в формате Х - *)
(* оно может быть создано программой xpaint *)
icon_bitmap_bits : array [0..59] of byte = (
$60, $00, $01, $b0, $00, $07, $0c, $03, $00, $04, $04, $00,
$c2, $18, $00, $03, $30, $00, $01, $60, $00, $f1, $df, $00,
$c1, $f0, $01, $82, $01, $00, $02, $03, $00, $02, $0c, $00,
$02, $38, $00, $04, $60, $00, $04, $e0, $00, $04, $38, $00,
$84, $06, $00, $14, $14, $00, $0c, $34, $00, $00, $00, $00
);
win_hints := XAllocWMHints();
if (win_hints=nil) then begin
writeln('XAllocWMHints - нет памяти');
halt(1);
end;
(* установим пожелания о состоянии окна, позиции его иконки *)
(* и ее виде *)
win_hints^.flags = StateHint OR IconPositionHint OR IconPixmapHint;
(* Загрузим заданное битовое изображение *)
(* и создадим из него пиксельную карту Х. *)
Pixmap icon_pixmap = XCreateBitmapFromData(display,
win,
PChar(icon_bitmap_bits),
icon_bitmap_width,
icon_bitmap_height);
if (icon_pixmap=nil) then begin
writeln('XCreateBitmapFromData: ошибка создания пиксмапа');
halt(1);
end;
(* Затем детализируем желаемые изменения. *)
(* в нашем случае - сворачиваем окно, определяем его иконку *)
(* и устанавливаем позицию иконки в левом верхнем углу экрана. *)
win_hints^.initial_state := IconicState;
win_hints^.icon_pixmap := icon_pixmap;
win_hints^.icon_x := 0;
win_hints^.icon_y := 0;
(* Передаем пожелания оконному менеджеру. *)
XSetWMHints(display, win, win_hints);
(* В конце необходимо освободить память из-под структуры. *)
XFree(win_hints);
Получить данные свойства можно с помощью ''XGetWMHints()''.
Атрибут, характеризующий "временное" окно.
Идентифицируется атомом ''XA_WM_TRANSIENT_FOR'' и имеет тип
''XA_STRING''. Свойство задается для окон, появляющихся на экране
для выполнения вспомогательных функций (диалоги, меню).\\
Такие объекты рассматриваются менеджером по особому.
Например, он может не добавлять к окну заголовок и рамку.
Данные свойства - идентификатор окна родительского по отношению к данному.
Задается свойство с помощью процедуры ''XSetTransientForHint()''.
Имена программы и ее класса, идентифицируется атомом
''XA_WM_CLASS'' и имеет тип ''XA_STRING''.
Данные свойства - структура типа ''TXClassHints''.
Задается свойство с помощью процедуры ''XSetClassHint()''
и может быть получено с помощью ''XGetClassHint()''.
Если окно (окна) программы имеют собственную цветовую палитру,
то приложение должно соответствующим образом задать для него
атрибут ''colormap''. Программа заносит идентификатор окна
(идентификаторы окон) в список, ассоциированный со свойством,
имя которого ''WM_COLORMAP_WINDOWS''.
Делается это процедурой ''XSetWMColormapWindows()''.
Получить список, уже находящийся в свойстве, можно, обратившись к
''XGetWMColormapWindows()''.
Когда окно открыто, пользователь посредством менеджера совершает над ним
разные действия. Программе может быть желательно перехватывать некоторые
из них. Так, например, если окно представляет собой редактор текста,
и пользователь пытается его закрыть, то разумно спросить у сидящего за
компьютером человека, а не желает ли он предварительно сохранить
результаты редакции. Начиная с X11R4 системой предусматривается
свойство с именем ''WM_PROTOCOLS''. Оно содержит список атомов,
и каждый из них идентифицирует свойство, связанное с действиями,
о которых надо оповещать программу. Эти свойства следующие:
* ''WM_TAKE_FOCUS'' - задается, если программа хочет передавать
фокус ввода между своими окнами самостоятельно; в этом случае менеджер
не будет управлять фокусом, ввода, а пошлет приложению событие
''ClientMessage'', у которого поле ''message_type''
равно атому, соответствующему свойству ''WM_PROTOCOLS'',
а поле ''data.l[0]'' равно атому, соответствующему свойству
''WM_TAKE_FOCUS''; в ответ на это событие программа должна
сама обратиться к ''XSetInputFocus()'' для задания окна,
имеющего фокус ввода;
''WM_SAVE_YOURSELF'' - задается, если программа хочет
перехватить момент своего завершения; менеджер окон посылает приложению
событие ''ClientMessage'', у которого поле ''message_type''
равно атому, соответствующему свойству ''WM_PROTOCOLS'',
а поле ''data.l[0]'' равно атому, соответствующему свойству
''WM_SAVE_YOURSELF''; в ответ программа может сохранить
свое текущее состояние;
''WM_DELETE_WINDOW'' - задается, если программа хочет
перехватить моменты, когда менеджер окон закрывает принадлежащие ей окна;
менеджер окон посылает приложению событие ''ClientMessage'',
у которого поле ''message_type'' равно атому,
соответствующему свойству ''WM_PROTOCOLS'', а поле
''data.l[0]'' равно атому, соответствующему свойству
''WM_DELETE_WINDOW''; далее программа сама решает,
оставить окно на экране или удалить его с помощью
''XDestroyWindow()''.
Свойство ''WM_PROTOCOLS'' задается процедурой
''XSetWMProtocols()'' и может быть получено с помощью
''XGetWMProtocols()''.
Приведем фрагмент программы, задающей свойство ''WM_PROTOCOLS''
и производящей соответствующую обработку событий.
. . . . . . .
var
prDisplay : PDisplay;
nScreenNum : integer;
prGC : TGC;
rEvent : TXEvent;
nWnd : TWindow;
pnProtocol : array [0..1] of TAtom;
nWMProtocols : TAtom;
(*
*Устанавливаем связь с сервером, получаем номер экрана,
*создаем окно, выбираем события, обрабатываемые программой
*)
. . . . . . .
(* Задаем свойство WM_PROTOCOLS *)
pnProtocol [0] := XInternAtom (prDisplay, 'WM_TAKE_FOCUS', True);
pnProtocol [1] := XInternAtom (prDisplay, 'WM_SAVE_YOURSELF', True);
nWMProtocols := XInternAtom (prDisplay, 'WM_PROTOCOLS', True);
XSetWMProtocols (prDisplay, nWnd, pnProtocol, 2);
(* Показываем окно *)
XMapWindow (prDisplay, nWnd);
(* Цикл получения и обработки событий *)
while true do
begin
XNextEvent (prDisplay, @rEvent);
case (rEvent.type) of
. . . . . .
ClientMessage :
begin
if (rEvent.xclient.message_type = nWMProtocols) then
begin
if (rEvent.xclient.data.l[0] = pnProtocol[0]) then
writeln('Receiving the input focus.')
else
if (rEvent.xclient.data.l[0] = pnProtocol[1]) then
begin
XCloseDisplay (prDisplay);
halt(0);
end;
end;
end;
. . . . . . .
end;
end;
. . . . . . .
Заказывается реакция на два события: получение фокуса
ввода (''WM_TAKE_FOCUS'') и
завершение программы (''WM_SAVE_YOURSELF'').
Когда сервер посылает событие первого типа,
задача печатает соответствующее сообщение на устройства вывода. При приходе
события второго типа, программа закрывает связь с сервером и
завершается.