Программирование в 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.

Приложение:
Исходный код программы winmove.pas