Программирование в X-Window
средствами Free Pascal
Авторы: А.П. Полищук, С.А. Семериков
[Оформление в HTML: Valery Votintsev]
Содержание
1. Основы программирования в системе X Window
1.1. Основные понятия
1.1.9. Операции над окнами
Манипулировать окнами можно не только с помощью атрибутов:
Xlib предоставляет набор функций для изменения их размеров,
перемещения на экране и в стеке окон, сворачивания и т.п.
Первая пара операций, которые можно применить к окну -
отображение или скрытие. Отображение окна заставляют окно появиться на
экране, скрытие приводит к удалению с экрана (хотя логическое окно в памяти
все еще существует). Например, если в вашей программе есть диалоговое окно,
вместо создания его каждый раз по запросу пользователя, мы можем создать окно
один раз в скрытом режиме и, когда пользователь запросит открыть диалог,
просто отобразить окно на экране. Когда пользователь нажимает
"OK " или
"Cancel ", окно скрывается. Это значительно быстрее создания и
уничтожения окна, однако стоит ресурсов, как на стороне клиента, так и на
стороне X сервера.
Отображение окна может быть выполнено с помощью
XMapWindow() , скрытие - с
помощью XUnmapWindow() . Функция
отображения заставит событие
Expose послаться программе, если только окно полностью не
закрыто другими окнами.
Другое действие, которое можно выполнить над окнами -
переместить их в другую позиции. Это может быть выполнено функцией
XMoveWindow() , которая
принимает новые координаты окна. Имейте в виду, что после перемещения окно
может быть частично скрытым другими окнами (или наоборот, открыто ими), и
таким образом, может быть сгенерировано сообщение
Expose .
Изменить размер окна можно с помощью функции
XResizeWindow() . Мы можем также
объединить перемещение и изменение размеров, используя одну функцию
XMoveResizeWindow() .
Все приведенные выше функции изменяли свойства одного
окна. Существует ряд свойств, связанных с данным окном и другими окнами. Одно
из них - порядок засылки в стек: порядок, в котором окна располагаются
друг над другом. Говорят, что окно переднего плана находится на верхе стека,
а окно заднего плана - на дне стека. Перемещение окна на вершину стека
осуществляет функция
XRaiseWindow() , перемещение окна на дно стека - функция
XLowerWindow() .
С помощью функции
XIconifyWindow() окно может быть свернуто, а с помощью
XMapWindow() -
восстановлено. Для того, чтобы понять, почему для
XIconifyWindow() нет обратной функции,
необходимо заметить, что, когда окно сворачивается, на самом деле оно
скрывается, а вместо него отображается окно иконки. Таким образом, чтобы
восстановить исходное окно, нужно просто отобразить его снова. Иконка
является на самом деле другим окном, которое просто тесно связано сильно с
нашим нормальным окном - это не другое состояние нашего окна.
Следующий пример демонстрирует использование операций над
окнами:
uses x,xlib,xutil,crt,dos;
(*
create_simple_window - создает окно с белым фоном заданного размера.
Принимает в качестве параметров дисплей, размер окна (в пикселях)
и положение окна (также в пикселях). Возвращает дескриптор окна.
Окно создается с черной рамкой шириной в 2 пикселя и автоматичсеки
отображается после создания.
*)
function create_simple_window(display : PDisplay;
width, height, x, y : integer): TWindow;
var
screen_num, win_border_width: integer;
win: TWindow;
begin
screen_num := XDefaultScreen(display);
win_border_width := 2;
(*
создаем простое окно как прямой потомок корневого окна экрана,
используя черный и белый цвета в качестве основного и фонового, и
размещая новое окно в верхнем левом углу по заданным координатам
*)
win := XCreateSimpleWindow(display, XRootWindow(display, screen_num),
x, y, width, height, win_border_width,
XBlackPixel(display, screen_num),
XWhitePixel(display, screen_num));
(* Отображаем окно на экране. *)
XMapWindow(display, win);
(* Заставляем выполниться все запросы к Х серверу. *)
XFlush(display);
create_simple_window:=win;
end;
//void main(int argc, char* argv[])
var
display: PDisplay; (* указатель на структуру дисплея Х *)
screen_num: integer; (* количество экранов для размещения окон *)
win: TWindow; (* дескриптор создаваемого окна *)
display_width, display_height: word; (* высота и ширина Х дисплея *)
win_width, win_height: word; (* высота и ширина нового окна *)
display_name: array [0..30] of Char;
name: string;
i: integer;
win_attr: TXWindowAttributes;
xx, y, scr_x, scr_y: integer;
child_win: TWindow;
(* переменная для хранения дескриптора родительского окна *)
parent_win: TWindow;
(* эта переменная будет хранить дескриптор корневого окна *)
(* экрана, на котором отображено наше окно *)
root_win: TWindow;
(* эта переменная будет хранить массив дескрипторов *)
(* дочерних окон нашего окна, *)
child_windows: PWindow;
(* а эта - их количество *)
num_child_windows: integer;
begin
name := getenv('DISPLAY'); (* имя Х дисплея *)
for i:=1 to byte(name[0]) do
display_name[i-1]:=name[i];
display_name[byte(name[0])]:=#0;
(* устанавливаем соединение с Х сервером *)
display := XOpenDisplay(display_name);
if (display = NIL) then begin
writeln(paramstr(0),': не могу соединиться с Х сервером ',
display_name);
halt(1);
end;
(* получаем геометрию экрана по умолчанию для нашего дисплея *)
screen_num := XDefaultScreen(display);
display_width := XDisplayWidth(display, screen_num);
display_height := XDisplayHeight(display, screen_num);
(* создаем новое окно в 1/9 площади экрана *)
win_width := (display_width div 3);
win_height := (display_height div 3);
(* отладочная печать в стандартный вывод *)
writeln('ширина окна - ', win_width, '; высота - ', win_height);
(* создаем простое окно как прямой потомок корневого окна экрана, *)
(* используя черный и белый цвета в качестве основного и фонового, и*)
(* размещая новое окно в верхнем левом углу по заданным координатам *)
win := create_simple_window(display, win_width, win_height, 0, 0);
XFlush(display);
(* отдохнем после трудов праведных *)
delay(3000);
(* пример изменения размеров окна *)
begin
(* в цикле уменьшаем окно *)
for i:=0 to 39 do begin
dec(win_width,3);
dec(win_height,3);
XResizeWindow(display, win, win_width, win_height);
XFlush(display);
delay(20);
end;
(* в цикле увеличиваем окно *)
for i:=0 to 39 do begin
inc(win_width,3);
inc(win_height,3);
XResizeWindow(display, win, win_width, win_height);
XFlush(display);
delay(20);
end;
end;
delay(1000);
(* пример перемещения окна *)
begin
(* вначале получаем текущие атрибуты окна *)
XGetWindowAttributes(display, win, @win_attr);
xx := win_attr.x;
y := win_attr.y;
(* затем находим окно родителя *)
begin
(* выполним запрос необходимых значений *)
XQueryTree(display, win,
@root_win,
@parent_win,
@child_windows, @num_child_windows);
(* мы должны освободить список дочерних дескрипторов, *)
(* так как он был динамически выделен XQueryTree() *)
XFree(child_windows);
end;
(* Транслируем локальные координаты в экранные, используя *)
(* корневое окно как окно, относительно которого выполняется *)
(* трансляция. Это работает потому, что корневое окно всегда *)
(*занимает весь экран, и его левый верхний угол совпадает *)
(* с левым верхним углом экрана *)
XTranslateCoordinates(display,
parent_win, win_attr.root,
xx, y,
@scr_x, @scr_y,
@child_win);
(* перемещаем окно влево *)
for i:=0 to 39 do begin
dec(scr_x,3);
XMoveWindow(display, win, scr_x, scr_y);
XFlush(display);
delay(20);
end;
(* перемещаем окно вниз *)
for i:=0 to 39 do begin
inc(scr_y,3);
XMoveWindow(display, win, scr_x, scr_y);
XFlush(display);
delay(20);
end;
(* перемещаем окно вправо *)
for i:=0 to 39 do begin
inc(scr_x,3);
XMoveWindow(display, win, scr_x, scr_y);
XFlush(display);
delay(20);
end;
(* перемещаем окно вверх *)
for i:=0 to 39 do begin
dec(scr_y,3);
XMoveWindow(display, win, scr_x, scr_y);
XFlush(display);
delay(20);
end;
end;
delay(1000);
(* пример сворачивания и восстановления окна *)
begin
(* сворачиваем окно *)
XIconifyWindow(display, win, XDefaultScreen(display));
XFlush(display);
delay(2000);
(* восстанавливаем окно *)
XMapWindow(display, win);
XFlush(display);
delay(2000);
end;
XFlush(display);
(* короткая передышка *)
delay(2000);
(* закрываем соединение с Х сервером *)
XCloseDisplay(display);
end.
Приложение:
Исходный код программы winmove.pas
|