blog · git · desktop · images · contact
2010-09-25
Beim letzten Posting zu Awesome ging es um die Verwaltung der Fenster von GIMP. Was ich dort gemacht habe, war aber letztlich nichts anderes, als das fertige "tile"-Layout geschickt zu beeinflussen.
Ein großer Teil der Funktionalität von Awesome steckt in Lua-Skripten, so auch die verschiedenen Tiling-Algorithmen. Die Entwickler haben dabei auch auf Einfachheit geachtet, was zur Folge hat, dass man sehr leicht eigene Layouts implementieren kann. Wie das geht, will ich hier anhand eines sehr simplen Beispiels beschreiben.
Wirft man einen Blick in die Datei
"/usr/share/awesome/lib/awful/layout/suit/floating.lua
", dann sieht
man, dass nur eine einzige Funktion namens "arrange()
" nötig ist sowie
ein Name ("name
") für das Layout. Es kann also direkt losgehen mit
einem ganz einfachen Dateirumpf, der vorerst nichts tut:
module("simple")
name = "simple"
function arrange(p)
end
Dies speichere man gemäß des angegebenen Modulnamens unterhalb von
"~/.config/awesome
" ab, in diesem Fall also als "simple.lua
".
Alternativ könnte man es auch ohne Modul und ohne extra Datei direkt in
der "rc.lua
" machen, indem man eine Tabelle entsprechend belegt -- so
finde ich es aber sauberer. Man kann es jetzt auch schon benutzen, indem
man es testweise auf irgendeinem Tag explizit setzt. Das geschieht zum
Beispiel an geeigneter Stelle in der der "rc.lua
" (nicht von späteren
Anweisungen überschreiben lassen ;)):
require("simple")
awful.layout.set(simple, tags[1][7])
"simple" ist dabei der Modulname. Es hätte also auch "vain.layouts.superfancy" heißen können, sofern entsprechende Dateien existieren würden.
Startet man Awesome nun über "[Mod]-[Shift]-R
" neu und wechselt auf
Tag Nummer 7 des ersten Bildschirms, wird man sehen, dass schon einmal
das Layout-Icon verschwunden ist. Klar, denn das benutzte Theme kennt
mit sehr hoher Wahrscheinlichkeit kein Layout namens "simple".
Interessanter ist es, ein Fenster zu öffnen. Huch? Man kann es nicht
verschieben -- obwohl der Code genau so im Original auch steht. Das
Floating-Layout ist leider ein Sonderfall, denn es ist im restlichen
Code fest verdrahtet. Das spielt aber keine Rolle, wenn man einen
Tiling-Algorithmus bauen will.
Die Funktion "arrange()
" muss nun die Fenster in Pixelkoordinaten
platzieren. Sowohl die sichtbaren Fenster als auch die Eigenschaften der
Arbeitsfläche sind im übergebenen Parameter versteckt, welcher eine
Tabelle ist, deren relevante Felder so aussehen:
p = {
workarea = { x, y, width, height },
clients = { ... },
...
}
"workarea
" ist der Bereich des Bildschirms, der uns zur Verfügung
steht -- wiboxes sind schon rausgerechnet. "clients
" ist eine weitere
Tabelle, die alle zu verwaltenden Clients enthält. Das sind alle
Informationen, die ein Tiling-Mechanismus benötigt. Das Grundprinzip ist
nun, über alle Clients in "clients
" zu iterieren und ihnen eine
Position und Größe zuzuweisen. Angenommen, man hat die Geometrie für
einen bestimmten Client namens "c
" berechnet, dann muss man eine
Tabelle mit diesen Informationen füllen und "geometry()
" am Client
"c
" aufrufen:
local wa = p.workarea
local g = {}
g.width = ...
g.height = ...
g.x = wa.x + ...
g.y = wa.y + ...
c:geometry(g)
Dieser letzte Funktionsaufruf ist das Kernstück und platziert das
Fenster. Die Punkte sind noch auszufüllen. "wa.x
" und "wa.y
" müssen
in dieser Form als Offset übernommen werden, da hiermit einerseits
wiboxes verrechnet werden, andererseits ist hierin auch die Platzierung
auf einem anderen Bildschirm versteckt.
Zurück zum konkreten Beispiel. Angenommen, es sollen alle Clients nebeneinander platziert werden. Dabei soll jeder die maximale Höhe einnehmen, in x-Richtung teilen sie sich den Platz gleichmäßig auf. Der Code dazu sähe so aus:
-- Hole ipairs() mit in die Umgebung, da dies nach module() nicht mehr
-- verfügbar ist.
local ipairs = ipairs
module("simple")
name = "simple"
function arrange(p)
-- Tippersparnis.
local wa = p.workarea
local cls = p.clients
for k, c in ipairs(cls) do
-- Teil der Geometrie, die für jeden Client gleich ist.
local g = {}
g.width = wa.width / #cls
g.height = wa.height
g.y = wa.y
-- Die Position in x-Richtung ist nun unterschiedlich. k ist ein
-- 1-basierter Index der clients-Tabelle. Das erste Fenster soll
-- bei (0, 0) sitzen, also muss 1 subtrahiert werden.
g.x = wa.x + (k - 1) * g.width
c:geometry(g)
end
end
Das ist alles. Jeder Client besitzt dieselbe Höhe und Breite. Auch die
Position in y-Richtung, "g.y
", ist für alle gleich: Sie sitzen am
oberen Rand des verfügbaren Workspaces. Das heißt, die Koordinaten des
Workspaces beginnen bei (0, 0)
in der linken oberen Ecke. Ferner sieht
man, dass die Tabelle der Clients sortiert ist und neue Clients an ihren
Anfang gesetzt werden. All die lästigen Details übernimmt Awesome. Man
muss sich nicht darum kümmern, wann diese Funktion aufgerufen werden
muss oder wie man vielleicht auf das Minimieren oder Maximieren von
Clients reagieren muss. Auch um die Breite des Borders um die Fenster
herum oder eine etwaige Titlebar muss man sich keine Gedanken machen.
Das Verschieben der Clients innerhalb der verfügbaren Slots, sei es mit
Tastatur oder Maus, wird einem ebenfalls abgenommen.
Bleibt nur noch zu klären, wie man dem Layout ein Icon zuweisen kann. Da
hierfür das "beautiful"-Paket genutzt wird (siehe
"/usr/share/awesome/lib/awful/widget/layoutbox.lua
"), muss diese
Information im benutzten Theme eingetragen werden. Zum Beispiel so:
...
theme.layout_simple = os.getenv("HOME") .. "/.config/awesome/simple.png"
...
Das Feld "layout_simple
" wird dabei bei Bedarf aus dem Namen, der ganz
am Anfang angegeben wurde, zusammengebaut.
Der hier gezeigte Tiling-Mechanismus ist natürlich trivial und nicht zu
gebrauchen. Aber ich hoffe, es ist klar geworden, wie einfach man eigene
Algorithmen einbauen kann. Auf diese Weise können auch mitgelieferte
Layouts verändert werden: Man kopiere die Datei aus dem
Systemverzeichnis in sein Home-Verzeichnis und ändere den Modulnamen.
Dann kann man sich austoben. Es muss nichts neu kompiliert und kein
Paket installiert werden, Awesome muss auch nicht beendet werden (er
lädt nur den Lua-Teil neu -- wenn man wollte, könnte man das neue Layout
auch über "awesome-client
" in Betrieb nehmen, das ist dann allerdings
nicht von Dauer).
Awesome!
– Nachtrag 29.11.2010: Im Paket awesome-vain gibt es einige sinnvollere Layouts.