Если такое окно верхнего уровня (который в действительности не окно верхнего уровня после того, как "удочерение" произошло) создано, приложение может создать в этом окне дочернее. Потомок может отображаться только в своем родительском окне - при перемещении его окно "обрезается" границей родительского. Любое окно может содержать более чем одно дочернее окно, и в этом случае эти окна упорядочиваются во внутренний стек. Когда окно верхнего уровня "поднимается", все его окна-потомки "поднимаются" вместе с ним, с сохранением их внутреннего упорядочения. Если окно потомка "поднято", оно поднимается только относительно своих собратьев.
Окна могут располагаться на экране произвольным образом, перекрывая друг друга. X имеет набор средств, пользуясь которыми программа-клиент может изменять размеры окон и их положение на экране. Особенностью системы является то, что она не имеет встроенной возможности управлять окнами с помощью клавиатуры или мыши. Чтобы это можно было осуществить, нужен специальный клиент, который называется менеджер окон (Window manager). Стандартный дистрибутив X содержит такую программу - twm. Возможности этого менеджера ограничены, но, тем не менее, он позволяет осуществлять базовые действия: передвигать окна с помощью мыши, изменять их размер и т.д. Более развитым оконным менеджером является, по всей видимости, программа mwm (Motif Window Manager), которая поставляется в рамках системы OpenMotif.
Но менеджер не может корректно управлять окнами, ничего о них не зная. В одних случаях удобно иметь заголовки окон, в других случаях окно не может быть сделано меньше определенных размеров, а в некоторых окно не может быть слишком увеличено. Окно может быть минимизировано (превращено в пиктограмму), в этом случае менеджер должен знать имя и вид пиктограммы. Для того, чтобы сообщить менеджеру свои пожелания относительно окон, клиенты могут использовать два способа. Во-первых, при создании окна X могут быть переданы рекомендации (hints) о начальном положении окна, его ширине и высоте, минимальных и максимальных размерах и т.д. Во-вторых, можно использовать встроенный в X способ общения между программами - механизм свойств.
1.1.4 Графические возможности X Window
Система X Window предназначена для работы на растровых дисплеях. В подобного рода устройствах изображение представляется матрицей светящихся точек - пикселей. Каждый пиксель кодируется определенным числом бит (как правило 2, 4, 8, 16 или 24). Число бит-на-пиксель называют "толщиной" или глубиной дисплея. Биты с одинаковыми номерами во всех пикселях образуют как бы плоскость, параллельную экрану. Ее называют цветовой плоскостью. X позволяет рисовать в любой цветовой плоскости (или плоскостях), не затрагивая остальные.
Значение пикселя не задает непосредственно цвет точки на экране. Последний определяется с помощью специального массива данных, называемого палитрой. Цвет есть содержимое ячейки палитры, номер которой равен значению пикселя.
X имеет большой набор процедур, позволяющих рисовать графические примитивы - точки, линии, дуги, выводить текст и работать с областями произвольной формы.
В X Window встроены средства для обеспечения обмена информацией между программами-клиентами. Для этого используется механизм свойств (properties). Свойство - это порция данных, связанная с некоторым объектом (например, окном), и которая доступна всем клиентам X.
Каждое свойство имеет имя и уникальный идентификатор - атом. Обычно имена свойств записываются большими буквами, например: MY_SPECIAL_PROPERTY. Атомы используются для доступа к содержимому свойств с тем, чтобы уменьшить количество информации, пересылаемой по сети между клиентами и X сервером.
В X предусмотрен набор процедур, позволяющих перевести имя свойства в уникальный атом, и, наоборот, по атому получить необходимые данные.
Некоторые свойства и соответствующие им атомы являются предопределенными и создаются в момент инициализации сервера. Этим атомам соответствуют символические константы, определенные в файлах-заголовках библиотеки Xlib. Эти константы начинаются с префикса XA_.
Продолжая традиции многих изданий, посвященных программированию, начнем с программы, рисующей на экране строку "Hello, world!". В этом примере приведены основные шаги, необходимые для работы в X Window.
uses x,xlib,x11,xutil,strings;
const
WND_X=0;
WND_Y=0;
WND_WDT=100;
WND_HGH=100;
WND_MIN_WDT=50;
WND_MIN_HGH=50;
WND_BORDER_WDT=5;
WND_TITLE='Hello!';
WND_ICON_TITLE='Hello!';
PRG_CLASS='Hello!';
(* SetWindowManagerHints - процедура передает информацию о свойствах программы менеджеру окон. *)
procedure SetWindowManagerHints(
prDisplay: PDisplay; (*Указатель на структуру TDisplay *)
psPrgClass: PChar; (*Класс программы *)
argv: PPChar; (*Аргументы программы *)
argc: integer; (*Число аргументов *)
nWnd: TWindow; (*Идентификатор окна *)
x, (*Координаты левого верхнего *)
y, (*угла окна *)
nWidth,
nHeight, (*Ширина и высота окна *)
nMinWidth,
nMinHeight:integer; (*Минимальные ширина и высота окна *)
psTitle: PChar; (*Заголовок окна *)
psIconTitle: PChar; (*Заголовок пиктограммы окна *)
nIconPixmap: TPixmap (*Рисунок пиктограммы *)
);
var
rSizeHints: TXSizeHints; (*Рекомендации о размерах окна*)
rWMHints: TXWMHints;
rClassHint: TXClassHint;
prWindowName, prIconName: TXTextProperty;
begin
if (XStringListToTextProperty(@psTitle, 1, @prWindowName)=0) or
(XStringListToTextProperty(@psIconTitle, 1, @prIconName)=0) then
begin
writeln('No memory!');
halt(1);
end;
rSizeHints.flags:= PPosition OR PSize OR PMinSize;
rSizeHints.min_width:= nMinWidth;
rSizeHints.min_height:= nMinHeight;
rWMHints.flags:= StateHint OR IconPixmapHint OR InputHint;
rWMHints.initial_state:= NormalState;
rWMHints.input:= True;
rWMHints.icon_pixmap:= nIconPixmap;
rClassHint.res_name:= argv[0];
rClassHint.res_class:= psPrgClass;
XSetWMProperties(prDisplay, nWnd, @prWindowName, @prIconName, argv, argc, @rSizeHints, @rWMHints, @rClassHint);
end;
(* main - основная процедура программы *)
//void main(int argc, char *argv[])
var
prDisplay: PDisplay; (* Указатель на структуру Display *)
nScreenNum: integer; (* Номер экрана *)
prGC: TGC;
rEvent: TXEvent;
nWnd: TWindow;
begin
(* Устанавливаем связь с сервером *)
prDisplay:= XOpenDisplay(nil);
if prDisplay = nil then begin
writeln('Can not connect to the X server!');
halt (1);
end;
(* Получаем номер основного экрана *)
nScreenNum:= XDefaultScreen(prDisplay);
(* Создаем окно *)
nWnd:= XCreateSimpleWindow(prDisplay, XRootWindow (prDisplay, nScreenNum), WND_X, WND_Y, WND_WDT, WND_HGH, WND_BORDER_WDT, XBlackPixel (prDisplay, nScreenNum),
XWhitePixel (prDisplay, nScreenNum));
(* Задаем рекомендации для менеджера окон *)
SetWindowManagerHints(prDisplay, PRG_CLASS, argv, argc, nWnd, WND_X, WND_Y, WND_WDT, WND_HGH, WND_MIN_WDT, WND_MIN_HGH, WND_TITLE, WND_ICON_TITLE, 0);
(* Выбираем события, обрабатываемые программой *)
XSelectInput(prDisplay, nWnd, ExposureMask OR KeyPressMask);
(* Показываем окно *)
XMapWindow(prDisplay, nWnd);
(* Цикл получения и обработки событий *)
while (true) do begin
XNextEvent(prDisplay, @rEvent);
case (rEvent.eventtype) of
Expose:
begin
(* Запрос на перерисовку *)
if (rEvent.xexpose.count ‹› 0) then continue;
prGC:= XCreateGC (prDisplay, nWnd, 0, nil);
XSetForeground(prDisplay, prGC, XBlackPixel (prDisplay, 0));
XDrawString(prDisplay, nWnd, prGC, 10, 50, 'Hello, world!', strlen ('Hello, world!'));
XFreeGC (prDisplay, prGC);
end;
KeyPress:
begin
(* Нажатие клавиши клавиатуры *)
XCloseDisplay(prDisplay);
halt(0);
end;
end;
end;
end.
Для сборки программы используется команда:
fpc hello.pas
Здесь fpc - имя исполняемого файла компилятора. Как правило, это символическая ссылка на реальное имя компилятора (например, ppc386).