tovotu

8. März 20121
Hübsche OSDs im Gnome-Stil mit Python
OS:Linux - Sprache:Python - Libs:PyCairo,PyGObject

Seit der Gnome-Desktop Anfang 2011 in der neuen Version 3 erschien und dabei die umstrittene Gnome-Shell mitbrachte, schmücken auf Tastendruck (etwa Lautstärke- oder Helligkeitsregler) halbtransparente "Bestätigungs-Blasen" die Desktops der Gnome-Benutzer (engl. confirmation bubbles; siehe z.B. im rechten Screenshot).

Entwickler und Hobby-Bastler können diese hübschen On Screen Displays (OSDs) allerdings nicht für ihre Zwecke dienstbar machen. Stattdessen heißt es auf Nachfrage zu dem Thema in Internetforen und Mailinglisten meistens, man solle auf die Terminal-Befehle zenity oder notify-send zurückgreifen, etwa so:

notify-send -i "test.svg" test

Diese Befehle erzeugen so genannte "Benachrichtigungs-Blasen" (engl. notification bubbles), die in der Gnome-Shell in der Regel wie folgt dargestellt werden:

Es existiert allerdings nicht nur ein optischer, sondern vor allem ein konzeptioneller Unterschied zwischen diesen Blasen [1]. Eine Benachrichtigung bekommt man zum Beispiel, falls eine neue Mail eingetroffen ist. Diese Benachrichtigung bleibt als Icon in der unteren rechten Ecke erhalten, bis der User in Interaktion mit ihr tritt, indem er beispielsweise mit der Maus darauf klickt und so das Fenster des Mail-Clients öffnet.

An allen gängigen Laptops gibt es eine Taste, um die Helligkeit des Displays zu verändern. Beim Druck auf eine solche Taste bekommt der Nutzer eine Bestätigung, die gerade nicht auf eine Reaktion des Nutzers wartet. Im Gegenteil soll die dabei erzeugte Blase den Benutzer möglichst nicht in seiner momentanen Tätigkeit behindern. Sie bekommt nicht den Fokus, d.h. Tastatur- und Mauseingaben werden vollständig an das darunterliegende Fenster weitergeleitet.

An neueren ThinkPads gibt es eine Taste, die das integrierte Mikrofon deaktiviert. Leider blendet Gnome beim Drücken dieser Taste momentan keine Bestätigungsblase ein. Ein kleines Python-Programm könnte diese Funktion bereitstellen. Die wesentlichen dafür benötigten Funktionen werden im Nachfolgenden besprochen. (Für eine generelle Einführung in PyCairo und PyGtk, bzw. seit Version 3 PyGObject, siehe z.B. [2] und [3].)

Alle wesentlichen Fenstereigenschaften entfernen

Das OSD lassen wir ein einfaches gtk.Window sein (im nachfolgenden win), bei dem die Fensterdekoration und die üblichen Interaktionseigenschaften vollständig entfernt wurden:

win.set_decorated(False)        # kein Rahmen 
win.set_resizable(False)        # fixe Fenstergeometrie
win.set_skip_taskbar_hint(True) # kein Eintrag in der Taskleiste
win.set_keep_above(True)        # in den Vordergrund zwingen...
win.set_accept_focus(False)     # ...und dennoch nicht den Fokus geben
win.stick()                     # auf allen Arbeitsflaechen anzeigen

Mausaktionen an das darunterliegende Fenster weiterleiten

Für diesen Teil muss man schon etwas tiefer in die Trickkiste greifen: Auf der Fläche des gesamten Fensters wird eine so genannte input shape definiert, innnerhalb derer Mauseingaben durchgelassen werden.

pm = gtk.gdk.Pixmap(None,win.get_size()[0],win.get_size()[1], 1)
pmcr = pm.cairo_create()
# Mit anderen Cairo-Zeichnungen liessen sich an dieser Stelle beliebig
# komplizierte "input shapes" definieren.
pmcr.rectangle(0,0,1,1)
pmcr.fill()
win.input_shape_combine_mask(pm, 0, 0)

Transparenz

Zunächst verpassen wir dem Fenster einen Alphakanal:

rgba = gtk.gdk.Screen.get_rgba_colormap(win.get_screen())
win.set_colormap(rgba)
win.set_opacity(win.alpha)

Der cairo.Context, auf den dann im Nachfolgenden gezeichnet werden soll (nennen wir ihn cr), wird jetzt komplett geleert - das Fenster ist danach völlig unsichtbar.

cr.set_operator(cairo.OPERATOR_CLEAR)
cr.rectangle(0.0, 0.0, size,size)
cr.fill()

An dieser Stelle sind die wesentlichen Schritte bereits getan. Auf den cairo.Context kann nun zunächst das halbtransparente Rechteck mit den abgerundeten Ecken gezeichnet werden. Danach zeichnet man darauf beliebige Icons oder fügt sie aus einer Bilddatei ein. Wie das konkret aussehen kann und wie man insbesondere Farben und Proportionen wählen muss, um die Bestätigungsblase der Gnome-Shell zu imitieren, kann man in meinem kleinen Beispielprogramm nachlesen. Eine so erstellte Bestätigungsblase könnte dann zum Beispiel so aussehen:

  1. wiki.ubuntu.com/NotifyOSD
  2. cairographics.org/tutorial
  3. zetcode.com/tutorials/pygtktutorial