====== Программирование в X-Window средствами Free Pascal ====== [[index|Перейти к содержанию]] ===== 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; (* Загрузим заданное битовое изображение *) (* и создадим из него пиксельную карту Х. *) Pixmap 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'' - задается, если программа хочет перехватить момент своего завершения; менеджер окон посылает приложению событие ''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''). Когда сервер посылает событие первого типа, задача печатает соответствующее сообщение на устройства вывода. При приходе события второго типа, программа закрывает связь с сервером и завершается.