"Программирование в X Window средствами Free Pascal" - читать интересную книгу автора (Полищук А. П., Семериков С. А.)

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.