Designing a Metacity theme is a relatively simple task, although tweaking it to meet your needs might prove somewhat time consuming. A Metacity theme is based on a defined XML format and, depending on a given theme, a number of images [generally Portable Network Graphic, PNG, file type].
The first step that you will need to do is to create a directory in either of the following places -
| $PREFIX/share/themes/[theme_name]/metacity-1/ | |
| $HOME/.themes/[theme_name]/metacity-1/ |
The next step to creating a Metacity theme is by editing a file within that directory called 'metacity-theme-1.xml'. This is the file that contains the XML description for the theme which has the following DTD description. When creating a new Metacity theme, it is useful to take an existing theme, copy across the xml description and then modify it, instead of creating a new theme entirely from scratch.
The first few lines of the format are -
Before we go into a detailed explanation of each part, we will give an overview of the steps taken.
There are 6 specific window types that Metacity recognizes -
| normal | a normal top-level window |
| dialog | a dialog window |
| modal_dialog | a dialog window that has modal state ie. intervention required by user before they can interact with it's parent window |
| menu | a pinnable menu window ie. tearoff menu |
| utility | a small persistant utility window ie. paletde or toolbox |
| border | a window that should not show any decorations typically ie. full screen window |
For each window type, you need to map a 'style set' [or window decoration] onto it. Each
'style set' is a composition of styles for several different 'frame states'. You will
need to specify how each of these frame states should look in your style. Frame states are
determined by the following -
| Whether the window is focused or un-focused | |
| Whether the window is maximized or shaded [or both] | |
| Whether the window can be vertically, horizontally, vertically and horizontally resized |
Each 'frame state' is mapped to a 'frame style'. A frame style is divided up into two different parts - frame 'pieces' and window 'buttons'. This seperation makes it easier to construct a Metacity theme.
If you omit any of the pieces, then nothing will be drawn for that piece. Metacity recognises the following
frame pieces -
| entire_background | the whole frame of the window which is drawn first |
| titlebar | area above the application's window |
| titlebar_middle | area of titlebar not considered an 'edge' piece |
| left_titlebar_edge | area to the left side of the titlebar |
| right_titlebar_edge | area to the right side of the titlebar |
| top_titlebar_edge | area to the top of the titlebar |
| bottom_titlebar_edge | area to the bottom of the titlebar |
| title | area containing the title |
| left_edge | the left edge of the frame |
| right_edge | the right edge of the frame |
| bottom_edge | the bottom edge of the frame |
| overlay | same as entire_background, only that it is drawn last |
Metacity recognizes the following window buttons -
| close | Close window button |
| maximize | Maximize window button |
| minimize | Minimize window button |
| menu | Menu button |
| and for the following button positions - | |
| left_left_background | Specifies the background of the 1st button on the left |
| left_middle_background | Specifies the background of the 2nd button on the left |
| left_right_background | Specifies the background of the 3rd button on the left |
| right_left_background | Specifies the background of the 1st button on the right |
| right_middle_background | Specifies the background of the 2nd button on the right |
| right_right_background | Specifies the background of the 3rd button on the right |
| Metacity window buttons |
For each button on your window, you must specify how they should appear under a given
number of button states. Metacity recognizes the following button states -
| normal | How the button should appear normally for a given frame state |
| pressed | How the button should appear when 'clicked' [with a mouse] |
| prelight | How the button should appear when it gets focus |
|
The last step to creating a theme is by specifying the menu icons. These appear in the window menu for the following entries -
|
|
||||||||||||||||||||||||||
|
When creating a Metacity theme, it is advisable to use an application especially designed for testing themes, metacity-theme-viewer. To use this application, simply provide the theme that you want to load as an argument. The theme you want to load gets parsed, and if there are errors, it will output any errors to the command line. You must fix any errors before a theme is successfully loaded. This application is really only useful when designing the style of the window decorations, since you will not be able to interact with the buttons or the window menus.
To switch to your new theme, you need to use either gconftool-2 or using the UI in Desktop Preferences >
Theme by selecting the 'Window Border Theme' tab. If using gconftool2-, you need to use the following
command -
gconftool-2 --type=string --set /apps/metacity/general/theme [theme_name]
|
|
The first thing you will need to create is the 'frame geometry'. The frame geometry name is referenced later on by a given
'frame style'.
The following diagram shows the various widths and heights that you can modify in a given frame
geometry -
| Frame geometry specifications |
The frame geometry has a number of optional attributes that you may provide -
| has_title | Determines whether the title text height should be included in the height calculator. This defaults to true if not specified. |
| title_scale | Uses Pango markup - xx-small, x-small, small, medium, large, x-large and xx-large. This defaults to pick up your desktop font if not specified. |
| rounded_top_left | Determines whether the top left corner of the window should be rounded. This defaults to false if not specified. |
| rounded_top_right | Determines whether the top right corner of the window should be rounded. This defaults to false if not specified. |
| rounded_bottom_left | Determines whether the bottom left corner of the window should be rounded. This defaults to false if not specified. |
| rounded_bottom_right | Determines whether the bottom right corner of the window should be rounded. This defaults to false if not specified. |
When specifying the frame geometry, it is possible to use inheritance. This simply overwrites any values that you
provide that are inherited from the parent.
Instead of specifying button widths and heights, you can specify an aspect ratio instead.
'drawing operations' are the heart of designing a Metacity theme. In order to successfully draw a part of the
frame, you will need to specify a drawing operation for that 'frame piece'.
Drawing operations are generally forward declared, but can also be placed inline [see example below]. The following
list of operators are allowed within a drawing operation -
| Operator | Meaning | Example | |
|---|---|---|---|
| + | Plus | 2 + 3 | |
| - | Minus | 5 - 4 | |
| * | Multiply | 3 * 2 | |
| / | Divide | 10 / 2 | |
| % | Modulus | 34 % 3 | |
| `max` | Maximum | 4 `max` 5 | |
| `min` | Minimum | 7 `min` 3 | |
| () | Parenthesis | (5 * 3) + 5 |
Within drawing operations, it is possible to use predefined variables or constants. Constants need to be forward
declared and must start with a capital letter.
The following is a list of predefined variables that can be used -
| width | Width of the target area |
| height | Height of the target area |
| object_width | Natural width of the object being drawn |
| object_height | Natural height of the object being drawn |
| left_width | Distance from left of frame to client window |
| right_width | Distance from right of frame to client window |
| top_height | Distance from top of frame to client window |
| bottom_height | Distance from bottom of frame to client window |
| mini_icon_width | Width of mini icon for window |
| mini_icon_height | Height of mini icon for window |
| icon_width | Width of large icon |
| icon_height | Height of large icon |
| title_width | Width of title text |
| title_height | Height of title text |
Metacity supports the following operations in any given drawing 'operation' -
| line | Draws a line with origin (x1, y1) and destination (x2, y2) and given color. Colors can be a color name like "blue", a hexadecimal number like "#FF0099" or a color from a GTK theme given as "gtk:base[NORMAL]" [See some more examples below]. It takes additional attributes width, dash_on_length and dash_off_length, which are both "0" by default. |
|
<line color="#00FF00" x1="3" y1="4" x2="0" y2="height" dash_off_length="2" dash_on_length="3"/>
|
|
| rectangle | Draws a rectangle with origin (x,y) and given width and height. It takes optional attributes filled, which is "false" by default. |
|
<rectangle color="blend/gtk:fg[NORMAL]/gtk:bg[NORMAL] x="0" y="0" width="width" height="height" filled="true"/>
|
|
| arc | Draws an arc with origin (x,y) and given width, height, start_angle and extent_angle. It takes optional attributes filled, which is "false" by default. |
|
<arc color="yellow" x="0" y="0" width="width-1" height="height-1" start_angle="30" extent_angle="180"/>
|
|
| tint | Applys a tint with origin (x,y) and given width, height, color and alpha. |
|
<tint color="orange" alpha="0.2" x="0" y="0" width="width - mini_icon_width" height="height"/>
|
|
| gradient | Draws a gradient with origin (x,y) and given width, height, type [either vertical, horizontal or diagonal] and any number of color elements. |
|
<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 | Maps an image to the element with origin (x,y) and given width, height and filename. It takes optional arguments alpha and colorize, which are "0" and no color by default. |
|
<image filename="my_image.png" x="0" y="0" width="width" height="height" alpha="0.5" colorize="#FF3399"/>
|
|
| gtk_arrow | Draws an arrow with origin (x,y) and given width, height, GTK state, shadow [none, in, out, etched_in and etched_out] and direction [up, down, left or right]. It takes optional argument filled, which is "false" by default. |
|
<gtk_arrow state="normal" x="2" y="2" width="width - 4" height="height" shadow="in" arrow="up" filled="true"/>
|
|
| gtk_box | Draws a box with origin (x,y) and given width, height, GTK state and shadow. |
|
<gtk_box state="normal" x="2" y="2" width="width - 4" height="height" shadow="out"/>
|
|
| gtk_vline | Draws a vertical line with origin (x,y1) and destination (x,y2) and GTK state. |
|
<gtk_vline state="normal" x="0" y1="0" y2="height"/>
|
|
| icon | Draws the window icon with origin (x,y) and given width and height. It takes optional argument alpha, which is "0" by default. |
|
<icon x="10" y="30" width="width / 3" height="height / 3" alpha="0.3"/>
|
|
| title | Draws the window title text with origin (x,y) and given color. |
|
<title x="10" y="30" color="gtk:text[NORMAL]"/>
|
|
| clip | Clips a given area with origin (x,y) and given width and height. |
|
<clip x="5" y="2" width="width - 10" height="height - SpacerHeight"/>
|
|
| include | Include other drawing operations with given name. It takes optional arguments (x,y), width and height, with defaults FIXME. |
|
<include name="other_drawing_operations"/>
|
|
| tile | Tile another drawing operations list with given name, tile_width and tile_height. It takes optional arguments (x,y), width, height, tile_xoffset and tile_yoffset with defaults FIXME. |
|
<tile name="other_drawing_operations" tile_width="10" tile_height="10"/>
|
|
When creating a 'frame style', you tie in the various different 'frame pieces' and 'window buttons' to a specific 'frame geometry'. We generally need to create a style for window states normal, maximized, shaded, maximized_and_shaded and depending on whether the window is in focus or not.
We first create a template that will contain all the information needed to draw a given frame style.
Inheritance is also allowed in a given frame style. Anything can be re-specified to override the parent style.
To draw parts of the frame, you will need to provide a drawing operation to each frame piece. If you omit a piece, then nothing will
be drawn for that part of the frame.
Alternatively, as mentioned earlier, you can provide a drawing operation inline.
The following diagrams shows the various pieces that you can style in a given frame -
| Non-title frame pieces |
| Titlebar frame pieces |
| Title frame piece |
As mentioned previously, you need to specify a minimum set of window buttons for a given theme. Drawing
methods must be provided for the close, maximize, minimize and menu buttons defined for each of the
two states - normal and pressed. If prelight is not specified, normal will be
used for that state.
Along with specifying the window buttons, you can can specify how to draw
part of the button depending on the position within the window frame. If
all your buttons have the same background, you need only specify drawing
operations for left_middle_background and right_middle_background.
Putting all this information together into a single 'frame style' might look like the following -
In the window menus you must specify icons for the menu entries Close, Maximize, UnMaximize and Minimize. It is enough to specify drawing operations for normal state only. You may optionally specify drawing operations for the other states, as mentioned above.
Once we have our various frame styles we need to map them onto the various window states. We do this by
creating a 'frame style set'. The name attribute is referenced later on by a a given 'window type'.
As you can see above, you must provide a frame for each of the window states, with window focus yes and no. The style attribute references your 'frame style'. You must also provide a resize attribute for any frames with a normal state with the value 'both'. You may optionally specify frames for other resize attributes none, horizontal and vertical.
The final mapping that you must provide is to map the 'window types' to given 'frame style sets'. Each window
type needs a style set - normal, dialog, modal_dialog, menu, utility
and border
As you can see, creating a Metacity theme will take a somewhat large amount of time. It is advisable to take existing themes and modify and observe the changes that you make gradually, instead of starting afresh. Many themes [Crux and Aqua being good examples] are based almost solely on images, which will be harder for you to modify. While a theme comprised of images might look at times very tempting, you must allow consider that it takes an appreciable amount of time to render the theme.
A good resource for Metacity themes is art.gnome.org. Bug reports should be made at bugzilla.gnome.org under the 'Metacity' component.
Metacity was written by Havoc Pennington and is licensed under the GNU General Public License [GPL]. This document was written by Glynn Foster, who has zero artistic talent, is licensed under the GPL and copyright 2002, Sun Microsystems Inc.