Современная электронная библиотека ModernLib.Net

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