Создание тем для Metacity

Перевёл с английского Виктор Вислобоков. Версия перевода от 09.01.2004

Содание тем для Metacity - это относительно простая задача, несмотря на то, что на неё вам придётся затратить некоторое время. Тема Metacity - это некий файл в формате XML и, в зависимости от конкретной темы и некоторое количество картинок [обычно в формате PNG].

Начало

Первый шаг - это создание подкаталога в одном из следующих каталогов:

  $PREFIX/share/themes/[theme_name]/metacity-1/
  $HOME/.themes/[theme_name]/metacity-1/

с названием, которое будет именем вашей темы. Несмотря та то, что Metacity найдёт тему в обоих вышеуказанных каталогах, целесообразным будет оставить тему в домашнем каталоге, пока вы будете писать и отлаживать её. Следующий шаг по созданию темы заключается в редактировании файла с именем 'metacity-theme-1.xml', который необходимо создать в каталоге темы. Это файл, который содержит XML описание темы, согласно данному DTD description. Для создания данного файла лучше воспользоваться существующей темой, скопировав указанный файл и затем модифицировав его, а не создавать новую тему с нуля. Первые несколько строк будут выглядеть так:
<?xml version="1.0"?>
<metacity_theme>
<info>
   <name>Atlanta</name>
   <author>Havoc Pennington</author>
   <copyright>Havoc Pennington, 2002</copyright>
   <date>September 2, 2002</date>
   <description>Atlanta- a simple theme using Gtk+ default theme</description>
</info>

   <!-- Эти строки нужны вам для начала описания вашей темы -->

</metacity_theme>

Разумеется, что вам необходимо будет заменить значения в тегах имя темы (в данном примере Altanta), а также автора (в данном случае Havoc Pennington) и т.д. на свои собственные.

Основы создания темы

Перед тем как погрузиться в детальное описание каждой части, сделаем краткий обзор.

Поддерживаемые типы окон

Существует 6 специальных типов окон, которые понимает Metacity:

normal обычноеl top-level окно
dialog диалоговое окно
modal_dialog диалоговое окно, которое является модальным, т.е. оно требует закрытия перед тем как пользователь сможет работать с родительским окном
menu окно меню
utility маленькое постоянное окно утилиты, например окно палитры или инструментов
border окно, которое обычно не должно иметь декоративное оформление, например окно полного экрана

Стили

Для каждого типа окна, вам необходима карта 'списка стилей' [или оформлений окна]. Каждый 'список стилей' представляет собой смесь стилей для нескольких различных 'состояний рамки' (имеется в виду четырехугольник, представляющий собой рамку окна). Вам необходимо определить, как каждое из этих состояний будет выглядеть в вашем стиле. Состояния рамки могут быть такими:

  Когда окно в фокусе или не в фокусе ввода
  Когда окно максимизировано или свёрнуто [или и то и другое]
  Когда у окна меняется размер по вертикали и горизотали или когда  оно двигается по  вертикали и горизонтали

Каждому 'состоянию рамки'  соответствует 'стиль рамки'. Стиль рамки подразделяется на две разные части - 'части' рамки и 'кнопки' окна. Такое разделение делает конструирование темы Metacity более лёгким.

Куски рамки

Если вы опустите любую из частей, то в этой части ничего прорисовано не будет. Metacity понимает следующие части рамки:


entire_background рамка окна целиком, которая будет прорисована в самом начале
titlebar область вверху окна приложения
titlebar_middle область titlebar которая не является 'edge'  (краевой) частью
left_titlebar_edge область с левой стороны titlebar
right_titlebar_edge область с правой стороны titlebar
top_titlebar_edge область в вверхней части titlebar
bottom_titlebar_edge область в нижней части titlebar
title область содержащая заголовок
left_edge левый край рамки
right_edge правый край рамки
bottom_edge нижний край рамки
overlay то же что и entire_background, но только прорисовывается в самом конце


Кнопки окна

Metacity понимает следующие кнопки окна:

close Кнопка закрытия окна
maximize Кнопка максимизации окна
minimize Кнопка минимизации окна
menu Кнопка меню
 
а также следующие параметры позиции этих кнопок
 
left_left_background Задаёт фон для первой кнопки слева
left_middle_background Задаёт фон для второй кнопки слева
left_right_background Задаёт фон для третьей кнопки слева
right_left_background Задаёт фон для первой кнопки справа
right_middle_background Задаёт фон для второй кнопки справа
right_right_background Задаёт фон для третьей кнопки справа

Metacity window buttons
кнопки окна Metacity

Для каждой  кнопки вашего окна, вы должны определить как кнопка будет выгляеть в каждом из своих состояний. Metacity понимает следующие состояния кнопок:

normal Обычное состояние кнопки в рамке
pressed Состояние кнопки 'clicked' когда по ней щелкнули мышкой
prelight Состояние кнопки когда она получает фокус


Меню окна

Последний шаг в создании темы состоит из определения значков меню. Они появляются в меню окна для следующих записей:

close Значок закрытия окна
maximize Значок максимизации окна
minimize Значок минимизации окна
unmaximize Значок демаксимизации окна
 
и следующих состояний, которые соответствуют GtkStateType
 
normal Как будет появляться в меню значок меню
prelight Как будет появляться значок меню, когда меню получает фокус
active Как будет появляться значок меню, когда активен пункт меню [напр. отмечен]
selected Как будет появляться значок меню, когда пункт меню выбран

Как будет появляться значок меню, когда пункт меню недоступен [серый цвет]
Metacity window menu
меню окнаMetacity

Тестирование темы

При создании темы для Metacity, рекомендуется использовать приложение metacity-theme-viewer, которое специально разработано для тестирования тем. Чтобы использовать это приложение, просто укажите в качестве аргумента ту тему, которую вы хотите загрузить. Эта тема будет загружена и проанализирована и если в ней будут ошибки, то вы увидите сообщения в командной строке. Вы должны исправить все ошибки перед тем как тема будет успешно загружена.

Данное приложение фактически полезно только при дизайне стиля декоративного оформления окна, так как вам не будут доступны действия, которые вы назначили кнопкам, а также окна меню.

Чтобы переключиться на вашу новую тему, используйте или gconftool-2
или интерфейс пользователя в Параметры -> Тема -> Theme details, выберите закладку 'Рамка окна'. При использовании  gconftool2-, вам
необходимо использовать следующую команду -

gconftool-2 --type=string --set /apps/metacity/general/theme [theme_name]

Metacity theme viewer application - for testing themes
Metacity theme viewer application - for testing themes

Глубоко внутри

Геометрия рамки

Первое, что вам нужно сделать - это создать 'frame geometry' (геометрию рамки). На имя геометрии рамки позднее будет ссылаться 'frame style' (стиль рамки).

<frame_geometry name="my_frame_geometry">

   <!-- This is where we need to start specifying your frame geometry -->

</frame_geometry>

Следующая диаграмма показывает разные размеры, которые вы можете изменять в геометрии рамки:

Frame geometry specifications
Frame geometry specifications

Геометрия рамки имеет несколько необязательных атрибутов, которые вы также можете определить:

has_title Определяет будет ли высота текста заголовка окна включена в калькулятор высоты. Если не задано, то значение по умолчанию true.
title_scale Использовать Pango markup - xx-small, x-small, small, medium, large, x-large и xx-large. Если не задано, то будет использоваться шрифт рабочего стола.
rounded_top_left Определяет будет ли скруглён верхний левый угол окна. Если не задано, то значение по умолчанию false.
rounded_top_right Определяет будет ли скруглён верхний правый угол окна. Если не задано, то значение по умолчанию false.
rounded_bottom_left Определяет будет ли скруглён нижний левый угол окна. Если не задано, то значение по умолчанию false.
rounded_bottom_right Определяет будет ли скруглён нижний правый угол окна. Если не задано, то значение по умолчанию false.

<frame_geometry name="normal_geometry">
   <distance name="left_width" value="6"/>
   <distance name="right_width" value="6"/>
   <distance name="bottom_height" value="7"/>
   <distance name="left_titlebar_edge" value="6"/>
   <distance name="right_titlebar_edge" value="6"/>
   <distance name="button_width" value="17"/>
   <distance name="button_height" value="17"/>
   <distance name="title_vertical_pad" value="4"/>
   <border name="title_border" left="3" right="12" top="4" bottom="3"/>
   <border name="button_border" left="0" right="0" top="1" bottom="1"/>
</frame_geometry>

После того как вы задали геометрию рамки, можно использовать наследование. Вот простое перекрытие любых значений, из тех, что были унаследованы от родителя.

<frame_geometry name="borderless_geometry" rounded_top_left="true" rounded_top_right="true" parent="normal_geometry">
   <distance name="left_width" value="0"/>
   <distance name="right_width" value="0"/>
   <distance name="bottom_height" value="0"/>
   <distance name="left_titlebar_edge" value="0"/>
   <distance name="right_titlebar_edge" value="0"/>
</frame_geometry>

Вместо задания размеров кнопок, вы можете задать только коэффициент перспективы.

<aspect_ratio name="button" value="1.0"/>

Операции рисования

'drawing operations' (операции рисования) являются основой при создании темы Metacity. Для успешного рисования части рамки, вам понадобиться задать операцию рисования для этой 'frame piece' (части рамки).

<draw_ops name="my_drawing_operation">

   <!-- This is where we need to start specifying your drawing operation -->

</draw_ops>

Операторы

Операции рисования обычно описываются вначале, но могут также быть встроены непосредственно в нужном месте [см. пример ниже]. Для операций рисования разрешается следующий список операторов:

Оператор Значение Пример
+ Плюс 2 + 3
- Минус 5 - 4
* Умножение 3 * 2
/ Деление 10 / 2
% Целочисленное деление
34 % 3
`max` Максимум 4 `max` 5
`min` Минимум 7 `min` 3
() Круглые скобки
(5 * 3) + 5
Ко всем операторам применимы нормальные правила приоритетов операций.

Константы

Внутри операторов рисования возможно использовать предопределённые переменные или константы. Константы должны быть перед этим объявлены и должны начинаться с денежного символа.

<constant name="MyConstant" value="3"/>

Может быть использован следующий список предопределённых переменных:

width Ширина области назначения
height Высота области назначения
object_width Реальная ширина рисуемого объекта
object_height Реальная высота рисуемого объекта
left_width Дистанция между левым краем рамки и клиентским окном
right_width Дистанция между правым краем рамки и клиентским окном
top_height Дистанция от верха рамки и клиентским окном
bottom_height Дистанция от низа рамки и клиентским окном
mini_icon_width Ширина минизначка для окна
mini_icon_height Высота минизначка для окна
icon_width Ширина большого значка
icon_height Высота большого знчака
title_width Ширина текста заголовка окна
title_height Высота текста заголовка окна

Операции

Для выполнения операций рисования Metacity поддерживает следующие виды 'operation' (операций):

line Рисует линию заданным цветом color от координат (x1, y1) до (x2, y2). Цвета можно указывать именами, типа "blue", шестрандцатеричным номером типа "#FF0099" или цветом из темы GTK, заданным в виде "gtk:base[NORMAL]" [См. примеры ниже]. Есть такие дополнительные атрибуты как width, dash_on_length и dash_off_length, которые по умолчанию устанавливаются в "0".
<line color="#00FF00" x1="3" y1="4" x2="0" y2="height" dash_off_length="2" dash_on_length="3"/>
 
rectangle Рисует четырёхугольник от (x,y) и с заданными шириной width и высотой height. Есть допольнительный атрибут filled, который по умолчанию установлен в "false".
<rectangle color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL] x="0" y="0" width="width" height="height" filled="true"/>
 
arc Рисует дугу начиная от (x,y) и с заднными шириной width, высотой height, начальным углом start_angle и вторым углом extent_angle. Есть допольнительный атрибут filled, который по умолчанию установлен в "false".
<arc color="yellow" x="0" y="0" width="width-1" height="height-1" start_angle="30" extent_angle="180"/>
 
tint Делает тон начиная от (x,y) и с заданными шириной width, высотой height, цветом color и альфа-каналом alpha.
<tint color="orange" alpha="0.2" x="0" y="0" width="width - mini_icon_width" height="height"/>
 
gradient Рисует градиент от (x,y) и с заданными шириной width, высотой height, типом type [vertical (вертикальный), horizontal (горизонтальный) или diagonal (диагональный)] и любым количеством элементов цвета color.
<gradient type="vertical" x="10" y="10" width="width - title_width" height="height / 4">
   <color value="blue">
   <color value="gtk:fg[SELECTED]>
   <color value="blend/gtk:light[SELECTED]/gtk:dark[ACTIVE]">
</gradient>
 
image Отображает картинку а элемент от (x,y) и с заданными шириной width, высотой height и именем файла filename. Существуют дополнительные аргументы альфа-канал alpha и колоризация colorize, которые по умолчанию установлены в значения  "0" и "нет цвета".
<image filename="my_image.png" x="0" y="0" width="width" height="height" alpha="0.5" colorize="#FF3399"/>
 
gtk_arrow Рисует стрелку от (x,y) и с заданными значениями ширины width, высоты height, состояния GTK state, тенью shadow [одно из значений none, in, out, etched_in и etched_out] и направлением direction [up, down, left или right]. Есть дополнительный аргумент filled, который по умолчанию имет значение "false".
<gtk_arrow state="normal" x="2" y="2" width="width - 4" height="height" shadow="in" arrow="up" filled="true"/>
 
gtk_box Рисует бокс от (x,y) и с заданными шириной width, высотой height, состоянием GTK state и тенью shadow.
<gtk_box state="normal" x="2" y="2" width="width - 4" height="height" shadow="out"/>
 
gtk_vline Рисует вертикальную линию от (x,y1) и до (x,y2) с состоянием GTK state.
<gtk_vline state="normal" x="0" y1="0" y2="height"/>
 
icon Рисует значок окна от (x,y) и с заданными шириной width и высотой height. Есть дополнительный аргумент альфа-канал alpha, по умочанию установленный в "0".
<icon x="10" y="30" width="width / 3" height="height / 3" alpha="0.3"/>
 
title Рисует заголовок окна от (x,y) с заданным цветом color.
<title x="10" y="30" color="gtk:text[NORMAL]"/>
 
clip Урезает заданную область от (x,y) и с зданной шириной width и высотой height.
<clip x="5" y="2" width="width - 10" height="height - SpacerHeight"/>
 
include Включает другие операции рисования с указанным именем name. Есть дополнительные аргументы (x,y), width и height, который по умолчанию имеют значение FIXME.
<include name="other_drawing_operations"/>
 
tile Выполнить черепицей список других операциё рисования с заданным именем name и значениями tile_width и tile_height. Есть дополнительные аргументы (x,y), width, height, tile_xoffset и tile_yoffset with. которые по умолчанию имеют значение FIXME.
<tile name="other_drawing_operations" tile_width="10" tile_height="10"/>


Стиль рамки

Во время создания 'frame style' (стиля рамки),  вы связываете разные 'frame pieces' (части рамки) и 'window buttons' (кнопки окна) со специальной 'frame geometry' (геометрией рамки). Обычно нужно создать стиль для таких состояний окна как normal, maximized, shaded, maximized_and_shaded и учитывая зависимость от такой вещи как: будет ли окно иметь фокус или нет.

Сперва создаём шаблон, который будет содержать всю информацию, которая необходима для рисования данного стиля рамки.

<frame_style name="my_frame_style" geometry="my_frame_geometry">

   <!-- This is where we need to start specifying your frame style -->

</frame_style>

При задании стиля рамки наследование также разрешено. Можно задать другой стиль, перекрывающий родительский.

<frame_style name="my_child_frame_style" parent="my_frame_style" geometry="my_frame_geometry">

</frame_style>

Части рамки

Чтобы отрисовать части рамки, для каждой части рамки вам нужно предоставить операцию рисования. Если вы опускаете какую-либо часть, то для этой части рамки ничего рисоваться не будет.

<piece position="entire_background" draw_ops="my_drawing_operation"/>

В качестве альтернативы, как отмечалось раньше, вы можете предоставить встроенную операцию рисования.

<piece position="left_edge">
   <draw_ops>
      <rectangle color="#FF0000" x0="0" y0="0" x1="width" y1="height" filled="true"/>
   </draw_ops>
</piece>

Следующие диаграммы показывают разные куски, которые могут иметь стиль в задаваемой рамке:

Non-title frame pieces
Незаголовчные куски рамки
 
 
Titlebar frame pieces
Titlebar frame pieces
 
 
Title frame piece
Заголовочные куски рамки

Кнопки окна

Как отмечалось ранее, для задаваемой рамки вам необходимо задать минимальный набор кнопок она. Методы отрисовки должны быть рпедоставлены для таких кнопок как close, maximize, minimize и menu, при этом для каждого из двух состояний - normal и pressed. Если prelight не задано, то для этого состояния будет использоваться normal .

<button function="close" state="normal" draw_ops="my_drawing_operation"/>

Перед заданием кнопок окна, вы можете определить как рисовать часть кнопки, в зависимости от позиции внутри рамки окна. Если все ваши кнопки имеют одинаковый фон, вам нужно задать только операции рисования для left_middle_background и right_middle_background.

<button function="left_middle_background" state="pressed" draw_ops="my_background_drawing_operation"/>

Если всю эту информацию поместить вместе в один стиль рамки 'frame style', то это может выглядеть так:

<frame_style name="my_frame_style" geometry="my_frame_geometry">

   <!-- We first display the title -->
   <piece position="title" draw_ops="title_normal"/>

   <!-- Let's give the edges some prettiness -->
   <piece position="left_edge" draw_ops="draw_left_edge"/>
   <piece position="right_edge" draw_ops="draw_right_edge"/>
   <piece position="bottom_edge" draw_ops="draw_bottom_edge"/>

   <!-- We need to specify the button positions now -->
   <button function="left_middle_background" state="pressed" draw_ops="background_button"/>
   <button function="right_middle_background" state="pressed" draw_ops="background_button"/>

   <!-- We need to specify the buttons now -->
   <button function="close" state="normal" draw_ops="close_button"/>
   <button function="close" state="pressed" draw_ops="minimize_button"/>
   <button function="minimize" state="normal" draw_ops="minimize_button"/>
   <button function="minimize" state="pressed" draw_ops="minimize_button_pressed"/>
   <button function="maximize" state="normal" draw_ops="maximize_button"/>
   <button function="maximize" state="pressed" draw_ops="maximize_button_pressed"/>
   <button function="menu" state="normal" draw_ops="menu_button"/>
   <button function="menu" state="pressed" draw_ops="menu_button_pressed"/>
</frame_style>

Значки меню

В меню окна вы должны задать значки для пунктов меню Close, Maximize, UnMaximize и Minimize. Достаточно задать только операции рисования для состояния normal. Вы можете дополнительно указать операции рисования для всех других состояний, как говорилось выше.

<window_icon function="close" state="normal" draw_ops="menu_close_icon"/>
<window_icon function="maximize" state="normal" draw_ops="menu_maximize_icon"/>
<window_icon function="minimize" state="normal" draw_ops="menu_minimize_icon"/>
<window_icon function="unmaximize" state="normal" draw_ops="menu_unmaximize_icon"/>

Список стилей рамки

После того как мы создали разные стили рамки, нам нужно отразить их на разные состояния окна. Это делается путём создания
 'frame style set' (списка стилей рамки). На атрибут name потом будет ссылаться заданный 'window type' (тип окна).

<frame_style_set name="my_style_set">
   <frame focus="yes" state="normal" resize="both" style="my_normal_focused_style"/>
   <frame focus="no" state="normal" resize="both" style="my_normal_unfocused_style"/>
   <frame focus="yes" state="maximized" style="my_maximized_focused_style"/>
   <frame focus="no" state="maximized" style="my_maximized_unfocused_style"/>
   <frame focus="yes" state="shaded" style="my_shaded_focused_style"/>
   <frame focus="no" state="shaded" style="my_shaded_unfocused_style"/>
   <frame focus="yes" state="maximized_and_shaded" style="my_maximized_shaded_focused_style"/>
   <frame focus="no" state="maximized_and_shaded" style="my_maximized_shaded_unfocused_style"/>
</frame_style_set>

Как видно выше, вы должны предоставить рамку для каждого из состояний окна и плюс при фокусе окна да и нет. Атрибут style ссылается на ваш 'frame style' (стиль рамки). Вы также должны предоставить атрибут resize, установленный в 'both' для всех рамок с состоянием normal.  Также можно дополнительно указать рамки для других атрибутов resize таких как none, horizontal и vertical.


Окна

Наконец, вы должны предоставить отражение 'window types' (типов окон) в заданные 'frame style sets' (списки стилей рамок). Для каждого типа окна  необходим список стилей - normal, dialog, modal_dialog, menu, utility и border

<window type="normal" style_set="my_normal_style_set"/>
<window type="dialog" style_set="my_dialog_style_set"/>
<window type="modal_dialog" style_set="my_modal_dialog_style_set"/>
<window type="menu" style_set="my_menu_style_set"/>
<window type="utility" style_set="my_utility_style_set"/>
<window type="border" style_set="my_border_style_set"/>

Обзор

Как видно, создание темы Metacity займёт довольно много времени. Лучше взять уже готовые темы и изменить в них то, что вы хотите, вместо того, чтобы писать тему с нуля. Многие темы [Crux и Aqua будут хорошими примерами] основаны также и на картинках, которые вам не так-то просто будет изменить. Хотя темы, которые используют картинки могут выглядеть очень соблазнительно, вы должны понимать, что отрисовка такой темы будет занимать больше времени.

Хорошим ресурсом по темам Metacity является art.gnome.org. Сообщения об ошибках оформляйте через bugzilla.gnome.org, выбрав компонент 'Metacity'.

Metacity написал Havoc Pennington по лицензией GNU General Public License [GPL]. Этот документ написал Glynn Foster, который не имеет таланта художника по лицензией GPL и copyright 2002, Sun Microsystems Inc.