# Metacity-Themen im Detail

## Einführung

Dies ist ein Artikel über die Erstellung von Themen für Metacity. Es wird noch daran gearbeitet, und es sind tiefgreifende Nachforschungen nötig, um Antworten zu finden. Es dürften Fehler enthalten sein, daher sind Korrekturen und Vorschläge herzlich willkommen.

GNOME lets you theme a bunch of different things, but we're only talking about `window border` themes here, which some people call Metacity themes; Wikipedia begins a sentence with "Despite the incomplete state of Metacity theme development documentation", and though there is documentation in the source, apparently not many people find it, and it's written more for programmers than theme designers. Glynn Foster also wrote a very good introduction to Metacity themes ([de]) six years ago, but things have changed a little since then. Metacity themes can also be used by Compiz, and perhaps by other window managers for all I know.

So ist ein Metacity-Thema eine Reihe von Anweisungen, wie ein Fenster »dekoriert« werden soll, also wie der Rahmen gezeichnet werden soll. Wir nehmen an, dass Sie nicht alle Fenster genau gleich gestalten wollen. Daher ermöglicht es das Format, Details für die verschiedenen Arten von Fenstern anzugeben.

Status:

- Jedes Fenster muss sich in exakt einem Status befinden: `normal`, `dialog`, `modal dialog` (beispielsweise ein Dialog, der die Interaktion mit dem übrigen Programm verhindert), `menu` (aus dem Hauptfenster ausgegliedert, wird heute nur noch selten benutzt), `utility` (Paletten, Werkzeugkästen und ähnliche Dinge) und `border`. X erlaubt auch, das ein Fenster explizit nicht dekoriert wird. Wir stellen für diese Fenster keine Dekorationsanweisungen bereit.

fokussiert

- Jedes Fenster ist entweder aktiv (»fokussiert«) oder nicht.

maximiert

- Jedes Fenster ist entweder (vollständig) maximiert (nur horizontal oder nur vertikal zählt nicht) oder nicht.

shaded

- Jedes Fenster ist entweder eingerollt und zeigt dabei nur seine Titelleiste (aus unerfindlichen Gründen von manchen Leuten »shaded« genannt) oder nicht.

- Falls ein Fenster nicht voll maximiert und nicht eingerollt ist, erlaubt es entweder horizontale Größenänderungen oder nicht.

- Falls ein Fenster nicht voll maximiert und nicht eingerollt ist, erlaubt es entweder vertikale Größenänderungen oder nicht.

## Inhalt der Datei

Die Datei muss entweder

- ~/.themes/`N`/metacity-1/metacity-theme-`V`.xml für ein von Ihnen verwendetes Thema heißen, oder

- /usr/share/themes/`N`/metacity-1/metacity-theme-`V`.xml für ein Thema, das für alle Benutzer installiert ist.

Dabei ist `N` der Name des Themas und `V` die Formatversion. Die im Oktober 2006 eingeführte Version 2 bringt einige neue Funktionsmerkmale mit, die aber selten genutzt werden. Version 1 ist das Originalformat. Die Formate wurden solange bearbeitet, bis genug Aufwärts- und Abwärtskompatibilität gegeben war. Neue Funktionen können nicht ohne neue Versionsnummer hinzugefügt werden. Daher kommen Verbesserungen recht selten, aber dafür in großen Brocken. `metacity-1` in den Namen ist ein Fossil und heißt keineswegs, das es sich in irgendeinem Zusammenhang um Version 1 handelt.

The metacity-theme-V.xml files are GMarkup files, which are very similar to XML. For now, you actually have to write these in a text editor or something; you can either start with a blank page, or modify a theme someone else has made. (I am thinking of writing a general theme editor program, but that'll have to wait until I've reduced Metacity's open bug queue a little.) If you want to see a fully-fledged one, you can look at the current version of "Atlanta", one of the simplest themes, but even that is quite complicated-looking at first.

Nun lassen Sie uns einen Blick darauf werfen, was sich derzeit in den Dateien befindet. Wie in jeder XML-Datei sind <!-- … > Kommentare. Grundlegend sieht es so aus:

    <metacity_theme>
    <!-- Helper stuff: -->
    <info …> <!-- to be explained -->
    <constant …> <!-- maybe; to be explained -->

    <draw_ops …> <!-- maybe; to be explained -->

    <!-- Things we build the top level onto: -->
    <frame_geometry …> <!-- to be explained -->

    <frame_style …> <!-- to be explained -->
    <frame_style_set …> <!-- to be explained -->

    <!-- And the top level: -->

    <window type="normal" style_set="…" />
    <window type="dialog" style_set="…" />
    <window type="modal_dialog" style_set="…" />

    <window type="menu" style_set="…" />
    <window type="utility" style_set="…" />
    <window type="border" style_set="…" />

    </metacity_theme>

## Matching windows

window

- In der obersten Ebene finden Sie eine Liste von <window>-Tags, einem für jeden erwähnten Fensterstatus. Das Argument style_set gibt jeweils den Namen eines frame_style_set an.

frame_style_set:

- Dies enthält Anweisungen zum Zeichnen der Fenster, abhängig davon, ob diese fokussiert sind oder nicht, eingerollt oder nicht, die vertikale oder horizontale Größenänderung oder Beides erlauben oder keines davon. Dies sieht so aus:

    <frame_style_set>
    <frame focus="F" state="S" resize="R" style="N"/>
    <frame… />

    …
    </frame_style_set>

wobei:

F

- yes für fokussiert steht, no für unfokussiert.

S

- die Flags »shaded« und »maximized« kombiniert: normal, maximized, shaded, oder maximized_and_shaded.

R

- Größenänderungsrechte repräsentiert, die vom Fenster vorgegeben werden: none, vertical, horizontal, oder both. Rahmeneinstellungen für maximierte Fenster, deren Größe nicht veränderbar ist, haben dieses Attribut nicht.

`N` ist der Name eines `frame_style`, der auf ein Fenster angewendet wird, das diese Attribute hat.

A `frame_style_set` tag may also have a "parent" tag, which should be the name of another `frame_style_set`. This means that if Metacity wants to know about a kind of window which that `frame_style_set` doesn't describe, it should look in the parent. Most of the more complicated tags in Metacity theme files also have a "parent" attribute which work the same way. This is particularly useful because, taken together, all the `frame_style_set`s in a theme file must be capable of matching every possible kind of window; if a window turns up that they can't match, there will be an error at runtime.

Let's recap what we've seen so far. The combination of a `window`, which matches a window's state (normal, dialog, and so forth), with an entry in the corresponding `frame_style_set`, which matches its focus, shadedness, maximisedness, and resize permissions where relevant, will allow you to make a list of rules to match any window against. The next piece of this puzzle lets you specify what Metacity should do with such windows once it's matched them.

## Actually drawing stuff

`frame_style:` Dies ist wahrscheinlich der komplizierteste Teil des ganzen Systems. Ein `frame_style` ist eine Reihe von `piece`s und `button`s. Es sieht so aus:

    <frame_style name="…" geometry="G">
    <piece position="P">
    <draw_ops>
    </draw_ops>
    </piece>
    …
    <button function="F" state="S" draw_ops="D"/>

    <draw_ops>
    </draw_ops>
    </button>
    …
    </frame_style>

Die `pieces` sind Teile des Fensterrahmens. Wenn Metacity einen Fensterrahmen zeichnet, dann werden die verschiedenen Teile immer in der gleichen Reihenfolge gerendert. Die fett dargestellten Teile sind die möglichen Werte von P:

- `entire_background`, gilt für de gesamten Fensterrahmen

- `titlebar`, gilt für den gesamten Hintergrund der Titelleiste

- `titlebar_middle`, der Teil der Titelleiste, der nicht die Ecken berührt

- `left_titlebar_edge`, `right_titlebar_edge`, `top_titlebar_edge` und `bottom_titlebar_edge`

- `title`, genau der Bereich, in dem in der Titelleiste der Text erscheint

- `left_edge`, `right_edge` und `bottom_edge`, die Ecken des Rahmens (es gibt keine top_edge: das wäre dann top_titlebar_edge, nicht wahr?)

- `overlay`, was alles abdeckt, etwa so wie entire_background, aber zuletzt anstatt zuerst ausgeführt

What Metacity draws in these pieces is decided by the theme. If a `frame_style` or its parents don't specify a particular piece, nothing will be drawn for that piece. You have two ways to specify what to draw: one is that the `piece` tag can have a `draw_ops` tag inside it which lists a sequence of drawing operations in Metacity's custom format. You might ask why we don't use SVG; one answer is that SVG support wasn't very strong when this format was designed, and another answer is that these days you can use SVG all you like; just include it as an image and Metacity will know what to do.

An alternative to including a draw_ops tag inside a piece tag is to add a draw_ops attribute to the piece tag. Then you can add a draw_ops tag at top level (inside the metacity_theme tag) with a name attribute, and Metacity will use that. This is useful if you use similar draw_ops over and over.

I'm not going to document draw_ops at present, because this is already very long. I will write it up later and link it from here.

The `button` tag tells Metacity how, but not where, to draw buttons. Buttons are drawn after all the pieces are finished, and the way to draw them is also given using draw_ops. You ought to provide buttons for all the possible kinds of button; if you don't give one it won't be drawn, which is unfortunate for the user who wants to use it:

- `left_left_background`, `left_middle_background`, and `left_right_background` don't represent buttons as such, but the background behind them, assuming there can be at most three buttons on the left. These days there can be more, so the extra ones also use left_middle_background.

- `right_left_background`, `right_middle_background`, and `right_right_background` similarly.

- `close`, `minimize`, `maximize` are the obvious original three buttons.

- `menu` is the menu button you can click to get a list of actions you can perform on the window.

- `shade`, `above`, `stick` are similar to the original buttons but only allowed in version 2

- `unshade`, `unabove`, `unstick` are the toggled versions of these buttons. Again, version 2 only.

The reason there are toggled versions of shade, above, and stick, and not maximize, is that by the time you get this far you've probably already decided whether you're drawing a maximised window. So if you are drawing a maximised window, you can make the button called "maximize" look how you want the restore button to be; otherwise, make it look like you want the maximise button to be.

For each button tag you should also set a "state" attribute; this time the state is either `normal` (the way you see it most of the time), `pressed`, or `prelight` (this makes the buttons subtly light up when you hover over them). You only really need "normal", but the others are good to have too.

The "geometry" attribute of a `frame_style` tag is the name of a…

## Geometrie

The `geometry` tag defines the sizes of things around the window. It is important, but not easy to explain, and again this file has gone on too long. I'll write it up later.

## Other things which lie around a file

The most important other thing in a theme file is the metadata held in the `info` tag. This contains a set of tags each of which contains some text explaining something about the theme itself, in a sort of Dublin Core sort of way. (Next time around, we should probably use the actual Dublin Core.) The tags are `name`, `author`, `copyright`, `date`, and `description`.

Version 1 of the format had a `menu_icon` tag at top level, which let themes specify the icons beside options in the menu you get from the menu icon. This has become redundant; the icons are taken from the icon theme! The tag can still be used in all formats, but does nothing and is deprecated.

Version 2 of the format has a `fallback` tag at top level, which let the theme specify what icon a window should be considered to have if it doesn't provide an icon of its own. This should also be taken from the icon theme, if anyone fancies fixing it, and the tag should also then be deprecated. It shouldn't be hard.

## When you're working on a theme

When you're editing a theme, you can view it without using it on the whole desktop using `metacity-theme-viewer YourThemeName`

and view it on the whole desktop using `gsettings set org.gnome.desktop.wm.preferences theme YourThemeName`

Whenever you change the selected theme in GSettings, Metacity will load the newly-chosen theme. This is how control-center does it. But when you change a theme, as you're working on it, you might want to ask Metacity to reload the theme which is currently used on the whole desktop to reflect your changes. You can do this using the little-known `metacity-message` program, with the command `metacity-message reload-theme`. This works by sending the ClientMessage `_METACITY_RELOAD_THEME_MESSAGE` to the root window, in case you're interested.

Once you're done with your theme, consider submitting it to the art.gnome.org site, or the gnome-look site.

## Die Zukunft

Please feel free to link to this so people don't have to keep asking the basic questions and can start asking the deeper ones. One of the important deeper ones is: where should we go in the future? Since this format is becoming something of a de facto standard between window managers, should we set up some kind of freedesktop.org standards discussion? Would it be useful to spin off Metacity's theme parsing code into a separate, LGPL-licensed library so that other applications could use it more easily?

What would a version 3 of this format look like? Could we simplify the window / frame_style_set system? (I can imagine abolishing both, and being able to write `<frame_style for="normal+unfocused+maximized">…` and having Metacity assume it applied to all resize permissions and shadednesses.) Maybe we should try to do everything with SVG we can? Getting more wild and handwavey, is it worth keeping XML-like? Maybe if other window managers were dealing with the files, .ini-style files would be more universally useful? Or perhaps not. And then of course we need a decent graphical editor for it. I have a few ideas, but if anyone fancies jumping in...