Программирование в X Window средствами Free Pascal
ModernLib.Net / Программирование / Полищук А. / Программирование в X Window средствами Free Pascal - Чтение
(стр. 5)
Наиболее простой является процедура XGetDefault(). Она получает имя программы, имя ресурса и определяет значение последнего. При этом она последовательно совершает следующие шаги: • сначала ресурс ищется в базе данных сервера (в свойстве XA_RESOURCE_MANAGER); • если он не найден, то значение ресурса определяется по файлу ".Xdefaults", который ищется в домашней (home) директории пользователя; • если задана переменная среды XENVIRONMENT, то ресурс ищется в файле, на который указывает эта переменная. Если ресурс одновременно встречается в ".Xdefaults" и файле, определяемом XENVIRONMENT, то берется последнее значение. В примере, приводимом ниже, используется XGetDefault(), чтобы получить строку, которую надо напечатать в окне программы. Предполагается, что имя программы - "hello", а строка - ресурс с именем "helloWorld", т.е. в файле ".Xdefaults" должна быть помещена, например, следующая запись: …
hello.helloWorld: Hello, World!
… Фрагмент программы, выполняющий чтение из файла ресурсов, будет выглядеть следующим образом: … prDisplay: PDisplay; prGC: TGC; nWnd: TWindow;
psString: PChar;
….
(* Устанавливаем связь с сервером, получаем номер экрана…*)
….
(* Выбираем события, обрабатываемые программой *)
XSelectInput (prDisplay, nWnd, ExposureMask
ORKeyPressMask);
(* Получаем рисуемую строку *)
psString:= XGetDefault (prDisplay, 'hello', 'helloWorld');
….
XDrawString (prDisplay, nWnd, prGC, 10, 50, psString,
strlen (psString));
…. Обратите внимание на то, что после изменения файла ".Xdefaults" он должен быть обработан программой xrdb для того, чтобы X сервер включил в свою таблицу обновленные ресурсы. Функция XGetDefault() проста в обращении, но недостаточно гибка. Так, например, с ее помощью нельзя прочитать содержимое произвольного файла ресурсов. Рассмотрим другие более развитые возможности. Вызов XrmInitialize() инициализирует менеджер ресурсов. Обращение к этой функции предшествует вызовам остальных процедур.
procedure XrmParseCommand(
prDB: TXrmDatabase
{database};
prOptRec: TXrmOptionDescList
{table};
nOptRecNum: integer
{table_count};
psProgName: pchar
{name};
argc: pointer
{argc_in_out};
argv: ppchar
{argv_in_out}
); cdecl; external;
сканирует строку, с помощью которой вызвана программа, и "достает" из нее ресурсы и их значения, при этом создается специальная структура данных - база данных ресурсов. Ресурсы и их значения помещаются в нее. Указатель на базу данных передается программе через переменную prDB. Параметр psProgName содержит имя программы, argc - число опций в командной строке, argv - сами опции. Аргумент prOptRec определяет, как разбирать командную строку. nOptRecNum задает число элементов массива prOptRec. В примере, приводимом ниже, определяется, что в командной строке опция "-bg" задает цвет фона; "-fg" - цвет переднего плана, а опция "-xrm" позволяет задать в командной строке любой ресурс программы. ….
const
rOptRec: array [0…2] of TXrmOptionDescRec = (
('-bg', '*background', XrmoptionSepArg, 'Red'),
('-fg', '*foreground', XrmoptionSepArg, 'White'),
('-xrm', NIL, XrmoptionResArg, NIL),
);
var
rDB: TXrmDatabase;
…
//void main (int argc, char **argv)
begin
…
XrmInitialize();
XrmParseCommand (rDB, rOptRec,
sizeof (rOptRec) / sizeof (rOptRec[0]),
argv[0], @argc, argv);
…
end.
Процедура XrmGetFileDataBase() позволяет считать указанный ресурсный файл и создать по нему в памяти базу данных ресурсов. Функция
function XrmGetResource(
prDB: TXrmDatabase
{database};
psResName: pchar
{str_name};
psResClass: pchar
{str_class};
psResType: ppchar
{str_type_return};
psResVal: PXrmValue
{value_return}
): Tbool; cdecl; external;
считывает ресурс с именем psResName и классом psResClass из базы данных *prDB. После возврата psResType есть указатель на строку, указывающую тип ресурса. На само значение ресурса указывает psResVal. Функция XrmPutResource() сохраняет ресурс в базе данных. XrmPutFileDatabase() записывает базу данных ресурсов в файл.
1.4.3 Лабораторная работа #4 "Программы и их ресурсы"
1. Составьте программу, считывающую из файла ресурсов маску шрифта, строку, координаты х, у и отображающую окно с текстом согласно полученной информации.
1.5 Межклиентское взаимодействие
1.5.1 Механизм свойств
Как мы уже упоминали ранее, свойство есть набор данных, ассоциированных с окном. Они хранятся в специальных таблицах в памяти компьютера, на котором работает сервер. Каждое свойство имеет имя. Разные окна могут иметь свойства с одинаковыми именами. Поскольку передача имен - строк произвольной длины - от клиента к серверу может увеличить нагрузку на сеть, X идентифицирует свойства с помощью целых чисел - атомов. Процедура XInternAtom() включает свойство с указанным именем в таблицу сервера и возвращает соответствующий атом. Полный список реализуемых X протоколом атомов можно найти в файле /usr/include/X11/Xatom.h. Данные свойства рассматриваются сервером как массив единиц длиной 8, 16 или 32 бита. Их конкретная интерпретация осуществляется программами-клиентами. Каждое свойство имеет тип, который, в свою очередь, также задается тем или иным свойством. Например, свойство, соответствующее атому XA_STRING, задает тип "строка". Для работы со свойствами кроме XInternAtom() используются следующие процедуры: XChangeProperty() - меняет данные свойства: XGetWindowProperty() - позволяет получить данные свойства. Особую роль играют свойства, данные которых содержат строки текста. Они так и называются текстовыми и имеют тип "TEXT". Таковыми являются, например, имена (заголовки) окно, имена пиктограмм и т.д. Данные текстового свойства описываются структурой TXTextProperty. Процедура XStringListToTextProperty() переводит список строк в набор данных типа TXTextProperty:
(* Эта переменная будет хранить созданное свойство. *)
var
window_title_property: TXTextProperty;
rc: TStatus;
(* Строка, преобразуемая в свойство. *)
const
window_title: PChar = 'hello, world';
(* перевод строки в свойство X. *)
rc:= XStringListToTextProperty(@window_title,
1,
@window_title_property);
(* проверка успешности преобразования. *)
if (rc = 0) then begin
writeln('XStringListToTextProperty - нет памяти');
halt(1);
end;
XTextPropertyToString() выполняет обратное преобразование.
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;
(* Загрузим заданное битовое изображение
и создадим из него пиксельную карту Х. *)
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 amp;mdash задается, если программа хочет перехватить момент своего завершения; менеджер окон посылает приложению событие 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). Когда сервер посылает событие первого типа, задача печатает соответствующее сообщение на устройства вывода. При приходе события второго типа, программа закрывает связь с сервером и завершается.
1.5.3 Лабораторная работа #5 "Межклиентское взаимодействие"
1. Составьте программу, которая при получении фокуса ввода перекрашивает свое окно в другой цвет. 2. Составьте программу, порождающую два расположенных рядом дочерних окна, в которых отображаются графики функций sin(x) на отрезке [0; 2?] и exp(x) на отрезке [-2; 2]. Графики масштабировать по размеру окон.
3. Создайте окно, изменяющее свои размеры таким образом, чтобы мышь всегда была в его центре. 4. Создайте окно, "убегающее" от указателя мыши.
5. Создайте программу, которая по нажатию клавиши мыши в основном окне создает новое окно (не более 100 одновременно), а по нажатию клавиши мыши в дочернем окне удаляет его. Если дочернее окно существует более одной минуты, оно должно самоудаляться.
6. Создайте программу моделирования эволюции клеточного автомата "Жизнь", ячейки которого имею два состояния: пусто и заполнено. Если рядом с пустой ячейкой три заполненных, она заполняется. Если рядом с заполненной ячейкой меньше двух или больше трех заполненных, ячейка становится пустой. Размеры модельного поля - 64Ч64 ячейки, вначале поле пустое. По нажатию любой кнопки мыши состояние ячейки меняется на противоположное, по нажатию пробела осуществляется один шаг эволюции, а по нажатии Escape - выход из программы.
Литература
Полищук А.П., Семериков С.А. Программирование в X Window. - Кривой Рог: Издательский отдел КГПУ, 2003. - 192 с. Полищук А.П., Семериков С.А. Событийно-ориентированное программирование. - Кривой Рог: КГПУ, 2001. - 336 с. Робачевский А.М. Операционная система UNIX. - К.: БХВ, 2000. - 518 с. Adrian Nye. Volume 0: X Protocol Reference Manual, 4rd Edition. - O'Reilly & Associates, 1990. - 446 p. Adrian Nye. Volume 1: Xlib Programming Manual, 3rd Edition. - O'Reilly & Associates, 1992. - 821 p. Adrian Nye. Volume 2: Xlib Reference Manual. - O'Reilly & Associates, 1992. - 935 p. Robert W. Scheifler & James Gettys. X Window System: The Complete Reference to Xlib, X Protocol, ICCCM, XLFD. X Version 11, Release 4. - Digital Press, 1992. - 711 p.
Страницы: 1, 2, 3, 4, 5
|
|