Springe zum Hauptinhalt

Love Boat - The Real Story. Haugesund

Tag 3. God morgen, Haugesund!

Wir legen pünktlich in Haugesund, unserem ersten und zugleich südlichsten Zwischenstopp, an und machen uns nach dem Frühstück zu unserem Landgang auf.

Haugesund havn

Wir schlendern durch die übersichtliche Innenstadt und nach dem üblichen Halt in der Touristeninformation, wir sind langjährig angelernte Individualtouristen, laufen wir zum kombinierten Monument Haraldshaugen (mit dem Obelisken Haraldstøtten) und Krosshaugen (mit dem Steinkreuz) in Erinnerung an die Herrschaft Königs Harald Hårfagre (Harald Schönhaar) und die Christianisierung des Landes.

Harald Hårfagre

Meine Mitreisenden entschließen sich zu einer Erholungspause nach dem Fußmarsch und ich versuche mich noch einmal an der Schlacht am Kuchenbuffet. Ich ziehe triumphierend mit Kuchen und Tee von dannen.

Dieser Teller wurde ohne Gewaltanwendung befüllt.

Am frühen Abend legen wir ab. Zum Abschied erfolgt das übliche Schallsignal '3x lang', gefolgt von Enyas "Orinoco Flow" und einem anderen musikalischen Begleitstück, das mir nicht bekannt ist. Uns steht sogleich der zweite Seetag bevor.

Abends frischt der Wind auf, im Nachhinein betrachtet läppische 7 Windstärken sorgen für die ersten Ausfälle bei den beiden männlichen Mitgliedern unserer Reisegruppe.

Das Rauschen des Meeres

Eine Schiffsreise unternimmt man vorsätzlich. Das Unterwegssein ist Teil der Destination. Die Umgebung Meer hat nachweislich positive entspannungsfördernde Effekte auf den Menschen, man kann Meeresrauschen auf Tonträgern erwerben oder aber einfach YouTube nutzen.

Das ist interessant, weil das Meer für den Menschen eigentlich ein lebensfeindliches Ökosystem voller Gefahren und damit eine natürliche Grenze darstellt. Wir empfinden das Rauschen des Wassers als faszinierend und verweilen im Starren auf die Bewegungen und Verwirbelungen der Wellen, die uns in Todesangst versetzen sollten, denn ohne den Schutz des Stahlkolosses um uns herum wären wir alle innerhalb von Minuten tot.

Friendship

Im Sommer bin ich einmal beim Segeln auf der Havel mit einem Freund in ein schnell durchziehendes, aber starkes Unwetter mit Windstärke 7 bis 9 geraten, das an Land schwere Schäden anrichtete. Wir konnten uns in einer Bucht positionieren, um mit minimaler Besegelung, eigentlich hätten wir noch eine weitere Reffstufe gebrauchen können, noch manövrierfähig zu sein und den Sturm über uns hinwegziehen zu lassen. Das hat auch gut funktioniert, war aber auch ziemlich abenteuerlich und hat uns ordentlich durchgeschüttelt und bis auf die Knochen nassgemacht.

Angesichts dieser Erfahrung schaue ich mir nun die Wellen an und versuche, das Gedankenspiel, das wir an Schönwettertagen auf dem Wasser gelegentlich durchsprechen, weiter zu denken. Also: wäre einem alles egal und würde das Boot Richtung New York nehmen, wie weit würde man mit der Nussschale (Friendship 24) kommen? Mit guter Vorbereitung und Equipment und etwas Glück mit dem Wetter kann man schon vorsichtig optimistisch werden, aber wenn es einen bei Windstärke 10 und 12 Meter hohen Wellen ausknockt oder von Deck haut, werden deine Überreste niemals irgendwo gefunden.

Das bringt mich zu einer weiteren Frage:

Wann fällt auf, dass einer fehlt?

Wie oft ich vor meinem Urlaub den Rat, nicht den Küblböck zu machen, gehört habe, habe ich nicht gezählt. Zur Info: Daniel Küblböck war eine Casting-Show-/Reality TV-Persönlichkeit, die im letzten Jahr eine letzte traurige Medienfußnote wurde, als sie von einem Kreuzfahrtschiff ins Meer sprang.

In einem Video eines Reisejournalisten wird erwähnt, dass jährlich bis zu 19 Personen weltweit von Kreuzfahrtschiffen verschwinden.

Von einem fahrenden Schiff aus auf dem Ozean ins Meer zu springen, ist eine sehr, sehr sichere Form des Selbstmords. Selbst wenn dies unter Zeugen geschieht, ist es nahezu unmöglich, einen Verunglückten im Auge zu behalten, falls dieser überhaupt noch bei Bewusstsein ist und wieder auftaucht, bis Rettungsmaßnahmen eingeleitet werden. Jeder, der schon einmal ein "Mann/Boje über Bord"-Manöver gemacht hat, dürfte dies nachvollziehen können.

Geht man ohne Zeugen über Bord, fällt das zunächst gar nicht auf.

Das rote Telefon

Crew

Am schnellsten fällt vermutlich der Verlust eines Crewmitglieds auf. Die Leute, die täglich die Außendecks in Schuss halten, arbeiten meiner Beobachtung nach tendentiell in Zweierteams. Diese Prämisse angenommen fällt ein fehlendes Teammitglied je nach Aufgabenverteilung innerhalb einer Arbeitsschicht auf. Da die Jungs und Mädels hier aber keinen 9 to 5-Job absitzen, kann das auch schon mal ein halber Tag sein. Spätestens zum Arbeitsbeginn am nächsten Tag dürfte es auffallen.

Zeitfenster: 0,5 - 24 Stunden? Oder gibt es Meldeintervalle für Außendeckcrew?

Passagier

Hier muss man wohl zwischen Alleinreisenden und Nichtalleinreisenden unterscheiden.

Da man sich an Bord frei bewegen kann, niemand abgehaltene oder ausgefallene Mahlzeiten überprüft und auch nicht gezwungen werden kann, in Häfen an Land zu gehen, wird man spätestens beim Auschecken am Ende der Reise vermisst werden. Aber es gibt ja auch noch das Housekeeping. Melden die, wenn eine Kabine eine Weile ganz offensichtlich nicht benutzt wurde? Prinzipiell ist es ja möglich, dass die Person in einer anderen Kabine nächtigt oder gar aufgrund von Beschwerden möglicherweise nur noch auf einem Barhocker sitzend...wer weiß das schon? Preisfrage: Schlägt jemand vom Housekeeping Alarm und wenn ja, wann? Ab dem ersten, zweiten, dritten Tag...?

Zeitfenster: ein bis mehrere Tage.

Für Nichtalleinreisende gilt vermutlich der Grad der sozialen Bindung als ausschlaggebend. Auf einem Kreuzfahrtschiff gibt es viele Rückzugsecken. Je größer das Schiff, desto höher ist die Wahrscheinlichkeit, sich nicht über den Weg zu laufen. Selbst auf der kleinen AIDAaura ist man neben bekannten Gesichtern auch bis zum Ende immer wieder neuen Mitreisenden begegnet, bei denen man hätte schwören können, diese in den vergangenen zwei Wochen noch nie gesehen zu haben.

Bei einem Ehepaar dürfte es bei der nächsten Mahlzeit, wohl spätestens bei angehender Nachtruhe, suspekt werden, wenn der andere abwesend ist. Bei einer losen Reisegruppe, die aus finanziellen Gründen gemeinsame Kabinen bezieht, mag eine Fremdübernachtung allein eventuell noch seltsam, aber unverdächtig erscheinen. Danach dürfte aber auch hier Unruhe aufkommen.

Zeitfenster: 1 bis 24 Stunden...?

Love Boat - The Real Story. Das Boot

Tag 2. Wochenend' und Sonnenschein

Die strahlende Wintersonne treibt die Passagiere in Scharen auf die Außendecks, eingemummelt in gelbe Fleecedecken wird sich in der Sonne entspannt als wäre man hier im Urlaub.

Informationsbedarfsermittlung

Nun geht es an die weiteren Planungen: was macht man eigentlich so an Bord? Welche Landausflüge sind interessant? Das AIDA-Bordportal wird ein stetiger Begleiter; in diesem findet man alle relevanten Informationen für das Leben an Bord - Zugriff aufs Bordkonto, Positionsdaten, Wetter, Kurs, Geschwindigkeit - wir beaufsichtigen jetzt die Machenschaften der Brücke -, Tagesplaner für Veransteltungen etc.

Zum Konzept der AIDA Selection-Reisen gehört ein durch Edutainment ergänztes Unterhaltungsprogramm, das sonst nicht zum Standardprogramm einer Kreuzfahrt dieses Anbieters zu gehören scheint. Bei dieser Fahrt dabei sind die Premium-Lektoren Georg Hahn, der über Geschichte, Land und Leute der Ziele referiert und Dr. Hartmut Renken, der mit kurzweiligen naturwissenschaftlich orientierten Vorträgen und Workshops den Passagieren die Zeit vertreibt.

AIDA-Feedback

Das Edutainment-Angebot habe ich als Bereicherung empfunden. Die Kombination aus historisch/gesellschaftlichen und naturwissenschaftlich orientierten Vorträgen hat meiner Beobachtung nach auch bei vielen anderen Passagieren Anklang gefunden. Aus persönlicher Sicht und Präferenz hätte es davon sogar mehr geben können, ich bin mit "traditioneller" Kreuzfahrt-Show-Unterhaltung aber auch grundsätzlich eher weniger zu begeistern. Bei einer zukünftigen Reiseplanung wäre dies ein Faktor, auf den ich Wert legen würde.

Kaffeecalypse

Nachmittags steht im Calypso-Restaurant "Kaffee und Kuchen" auf dem Plan, das klingt doch nach einem gemütlichen Beisammensein. Bei der Ankunft stellen wir fest, dass der Rest des Schiffes bereits anwesend ist. Es herrscht ein unfassbares Gedränge am fast erschöpften Kuchenbuffet, an den Tischen gibt es keine freien Plätze. Die Stimmung auf dem Bahnhof Roßlau nach der vierten Verspätungsansage ist entspannter.

Ich habe einen vermeintlich cleveren Plan und beschließe, dass wir an einem freien Platz im Außenbereich des Restaurants Platz nehmen und ich uns etwas von drinnen organisiere. Allein bin ich einfach wendiger.

Getränke-Flatrate, die Zweite

Da die Kaffeekannen auf den Tischen von Bluthunden verteidigt werden, trete ich an den Kaffeeautomaten der Getränkestation heran. Was nicht nur mich etwas stutzig macht, ist, dass man die Bordkarte einführen soll, keine Getränkekarte.

Und so ist es auch: die Kaffees aus den Automaten der Restaurants werden über das Bordkonto abgerechnet. Bestellt man hingegen Kaffee in den Bars, sind diese von der Getränkeflat gedeckelt. Klingt komisch, ist aber so.

Nach einer Bestellung eines alkoholfreien Biers ist erneute Verwirrung angesagt, denn dieses ist wieder nicht in der Getränkeflat enthalten. Eine Nachfrage an der Rezeption ist geklärt, dass nur Getränke aus dem offenen Ausschank enthalten sind. Das heißt:

->  X wird in Flaschen serviert: nicht von der Getränkeflat gedeckelt
->  X wird in einen alkoholfreien Cocktail geschüttet: von der Getränkeflat gedeckelt

Klingt komisch, ist aber so.

AIDA-Feedback

Als Mitarbeiter oder auch als routinierter Passagier mag man dieses Vorgehen verinnerlicht haben. Zur besseren Transparenz wäre es meiner Ansicht nach einfach und simpel umsetzbar, dies in der Getränkekarte zu markieren.

Dinnerdisaster

Mit einem Dreijährigen unterwegs zu sein, macht einiges komplizierter. Er ist zu groß, jederzeit mit Fertigfutter befriedet und anschließend geparkt werden zu können und zu klein, um sich an die Bedürfnisse der Erwachsenen anzupassen.

Das Abendessen wird in den Restaurants zwischen 18 und 21 Uhr angeboten. Es gibt das Selection-Restaurant mit täglich wechselndem À la carte-Service, die anderen beiden Restaurants bieten reichhaltige Buffets mit ebenfalls täglich wechselnden Themenschwerpunkten.

Die Gästedynamik hatten wir bis zu diesem zweiten Tag noch nicht durchschaut bzw. keiner besonderen Beachtung verliehen. Das rächte sich nun.

Gutgelaunt suchten wir gegen 19 Uhr das Calypsorestaurant auf. Unsere Gelassenheit schlägt sich in Irritation um, denn wir finden für unsere fünf Personen keinen freien Tisch, an dem wir Platz nehmen könnten. In der Hoffnung, dass es für nur drei Personen einfacher sein würde, einen Platz im Marktrestaurant zu finden, schlage ich also eine Aufteilung unserer Reisegruppe vor. Zwei Minuten später kommt mir kopfschüttelnd K. entgegen "Die sitzen alle vor ihren (Wein-)Gläsern".

In diesem Moment erschließt sich mir, warum das Marktrestaurant abends für eine halbe Stunde eine Pause einlegt - um 19:30 Uhr wird kurz geschlossen, neu eingedeckt und ab 20 Uhr kann man das nun leere Restaurant betreten und hat eine Chance auf einen Platz.

Für den Kleinen erweist sich diese Option als zu spät, das Abendessen wird zum nervenzehrendem Abschnitt des Tages.

AIDA-Feedback

Die halbstündige Pause im Marktrestaurant erweist sich als absolut notwendig. Als Ergänzung oder Alternative könnte man ein paar "Kindertische" einrichten (zum Beispiel hinter dem Eingang gleich links), in deren Nähe zum Beispiel auch Sitzerhöhungen bereit liegen und an denen Familien mit kleinen Kindern Vorrang haben. Den Vorrang könnte man ganz zwanglos erreichen, indem dies explizit als Tische ohne Weinausschank deklariert wären. Dies könnte auch für trockene Alkoholiker interessant sein.

Ausgang

Baby, it's cold outside...

Nach einem ganzen Tag auf See und dem Stress beim Abendessen mache ich mich zu einem Spaziergang über die äußeren Decks auf. Um zu beweisen, dass ich auf Wasser laufen kann, loggt Strava mit. Ich mache also einen 70-minütigen Spaziergang in Schlangenlinien auf dem Wasser in einem Mordstempo...das macht mir so schnell keiner nach!

Nach der Tour schaue ich in der AIDA Bar vorbei, in der zu meiner Überraschung K. und M. am Discofox-Marathon teilnehmen und das Ding schließlich gewinnen. Kreuzfahrtatmosphäre voraus!

Love Boat - The Real Story

Prolog

Der von langer geplante Familienurlaub zu den Polarlichtern naht. Es war ziemlich schnell klar, dass es eine Kreuzfahrt werden soll. Erwähnt man in Gesprächen diese Reise, ist die zwingend darauf folgende Einwortfrage "Hurtigrouten?". Die Einwortantwort darauf ist "Nein.", die längere Ausführung ist "Nein, wir haben uns für AIDA entschieden, primär wegen der einfachen An- und Abreise innerhalb Deutschlands. Ja, ich glaube schon, dass sich der Ballermann-Charme auf dieser Route in Grenzen halten wird."

Die Reise heißt "Winter im hohen Norden" und seit 2017 beim Kreuzfahrtveranstalter im Programm. Zwei Reiseberichte aus dieser ersten Saison findet man hier:

Hinweise

  1. Aus meinen Notizen ist ein unerwartet langer Bericht geworden (>5000 Wörter), den ich in mehrere Artikel unterteilt habe. Eine einseitige Darstellung findet man hier.
  2. Ursprünglich hatte ich einige Stichpunkte auch für das AIDA-Feedback-Formular selbst festgehalten. Die habe ich beibehalten. Falls hier also AIDA-Mitarbeiter mitlesen sollten, die Wege der Daten sind schließlich unergründlich, in einer blauen Box.
  3. Persönliche Tipps oder Randnotizen erscheinen in einer orangefarbenen Box.

AIDA-Feedback

... diese blauen Boxen sind für euch.

Ankes Tipps

... sehen so aus.

{!posts/norge01.md!}

Nikola-Import-Plugin für Google+

Bemerkung

Der Countdown des Shutdowns läuft nun endgültig. Der Artikel wurde hinsichtlich einiger Veränderungen ergänzt:

  • Importfilter

  • Konfigurationsdatei

  • Post-Analyse mit der Option -s

  • Wasserzeichen zu Imagedateien hinzufügen

Das Ende ist nah

Häufig wurde das Ende von Google+ herbeigeunkt. Nun, da es tatsächlich am 2. April 2019 so weit ist, weicht Geschäftigkeit dem ersten Schock.

In weiser Vorraussicht beschäftigte ich mich bereits vor einer Weile damit, die Daten brauchbar zu konservieren und entschied mich für eine Lösung mit dem statischen Webseitengenerator Nikola: Verloren im Kaninchenbau von Google Takeout.

/images/takeout_gplus_slow.gif

Resultat der Nikola-generierten Seite mit hyde-Thema

Vorbereitungen

Google Takeout

Zunächst benötigt man die Daten aus dem Takeout. Da sich hier große Datenmengen ansammeln, ist es ratsam, keine weiteren außer Googe+-relevanten Produkte auszuwählen:

  • Button "Nichts auswählen", dann "Stream in Google+" aktivieren

  • Als Dateiformat HTML wählen

  • Als Archivformat zip wählen, bei tar.gz kann es Encodingprobleme geben

  • Nach Fertigstellung kann das/die Archiv/e heruntergeladen und entpackt werden

  • die index.html gibt Hinweise auf Fehler bei der Archiverstellung

Nikola

  1. Installation:

    Nikola kann über pip oder je nach verwendeter Distribution über die Paketverwaltung installiert werden: Getting Started.

  2. Initialisierung:

    Das Plugin kann in einer bestehenden mit Nikola verwalteten Webseite erstellt werden. Es ist aber auch möglich, für diesen Verwendungszweck eine neue leere Seite zu erstellen, die dann später wieder gelöscht wird:

$ nikola init gplus_dummy_site
  1. Plugin installieren:

    Zuerst das Plugin als Archiv herunterladen und entpacken oder das Repository klonen: encarsia/gplus_nikola_import. Anschließend muss man noch den Ordner in die im vorigen Schritt angelegten Seite in den noch anzulegenden plugins-Ordner kopieren.

  2. Optional: Um die Übersicht zu behalten, kann man auch den Takeout-Ordner in die Nikola-Seite verschieben.

Import ausführen

Dateistruktur

Vor dem Ausführen des Imports öffnet man zunächst die Konfigurationsdatei config.yaml. Hier lassen sich zum Beispiel Filteroptionen einstellen.

Die Ordnerbezeichnungen entsprechen der deutschen Spracheinstellung des Takeouts, bei abweichender Spracheinstellung muss man hier die entsprechenden Bezeichnungen der Dateistruktur anpassen.

Es werden Beiträge nach Verteilungsstatus unterschieden:

  1. Öffentlich geteilt

  2. Mit Meinen Kreisen geteilt

  3. Mit Erweiterten Kreisen geteilt

  4. Mit bestimmten Kreisen oder Personen/Profilen geteilt

  5. Beiträge in Communites

  6. Beiträge in Sammlungen

Tipp

Um sich einen Überblick zu verschaffen, kann man die die Plugin-Option -s nutzen. Damit werden die Verteilungsstatus aller Beiträge analysiert und aufgelistet, ohne dabei den eigentlichen Import auszuführen.

$ nikola import_gplus_html -s takeout
[...]
************************************************
*                                              *
* Share information of your G+ Takeout archive *
*                                              *
************************************************

=======
General
=======

(edit the "shared" section of your config.yaml)

Geteilt mit: Öffentlich (1832)
Shared to the community (704)
Shared to the collection (429)
[...]

===========
Communities
===========

(edit the "import" section of your config.yaml:
    > set "com" to True to include communities
    > exclude communities by listing them in "com_filter")

E-Book (275)
Das Gruselkabinett des Dr. Goo (196)
Deleted community (65)
[...]

===========
Collections
===========

(collections are considered public so this is FYI only)

Zapping (66)
Street|p|arts (61)
Unterwegs (54)
[...]

Beiträge filtern

Mit der Option import_private lässt sich einstellen, ob mit bestimmten Kreisen oder Personen/Profilen geteilte Beiträge importiert werden sollen.

Die Option import_com schaltet den Import von Communitybeträgen ein oder aus. Dabei wird nicht nach öffentlichen oder geschlossenen Communities unterschieden.

/images/GPlus_plugin/watermark.jpg

Albrecht-Daniel-Thaer-Saal

Bilddateien markieren

Falls man sein Archiv öffentlich zur Verfügung stellen möchte, mag es hilfreich oder erwünscht sein, Bilddateien mit einem Wasserzeichen oder Hinweis auf den Ursprung zu versehen.

Dafür setzt man watermark auf True und legt eine Textzeile fest (watermark_text). Dies erzeugt mit Hilfe von ImageMagick ein horizontales Textbanner für alle Bilder.

Die Dateien werden in einem separaten Ordner erstellt, ohne die Originaldateien zu überschreiben. Das bedeutet, man kann den Build-Prozess beliebig für beide Optionen laufen lassen, ohne den Import erneut ausführen zu müssen.

Import

Im gplus_dummy_site-Verzeichnis führt man nun den Import aus, dabei wird als Argument der Ordner des entpackten Takeout-Verzeichnisses übergeben:

$ nikola import_gplus_html path/to/takeout_folder

Nikola initialisiert eine neue Seite namens "new_site", dort werden alle Posts, die dazugehörigen Metadaten und die Mediendateien gespeichert.

Mit der Option -o lässt sich ein individueller Name für die neu angelegte Seite vergeben. Dies ist praktisch, wenn man zum Beispiel verschiedene Versionen der selben Ausgangsdaten erstellen möchte.

Statische Seite erstellen

conf.py

Nun wechselt man in das Verzeichnis der neuen Nikola-Instanz (standardmäßig "new_site").

Dort befindet sich die Konfigurationsdatei conf.py. In dieser lassen sich nun Anpassungen vornehmen. Da im Beispiel das Thema hyde verwendet wird, wird dieses hier gleich angepasst, außerdem die Auslieferung des RSS-Feeds deaktiviert:

THEME = "hyde"
GENERATE_RSS = False

Thema

Hyde ist ein persönlicher Favorit und wird deshalb hier installiiert:

$ nikola theme -i hyde

Im Pluginordner befindet sich eine CSS-Datei custom.css, die einige optische Anpassungen für diesen Anwendungsfall enthält, diese einfach in das Verzeichnis themes/hyde/assets/css kopieren.

Grundsätzlich funktioniert die Seite mit jeden Theme. Eine Liste der verfügbaren Themes erhält man folgendermaßen:

$ nikola theme -l   # installierbar
$ nikola theme --list-installed     # installiert

Um ein Thema zu verwenden, muss es in der conf.py angegeben und die Seite neu gebaut werden. Ein erneuter Datenimport ist natürlich nicht notwendig.

Bilder

Möchte man die Bilddateien mit Textbanner verwenden, muss in der conf.py noch der entsprechende Ordner zugewiesen werden:

IMAGE_FOLDERS = {"images_wm": "images"}

Bei einem größeren Bildervolumen ist es eventuell sinnvoll, die Bild- und Thumbnailgröße einzuschränken:

MAX_IMAGE_SIZE = 800  # default 1280
IMAGE_THUMBNAIL_SIZE = 200   # default 400

Build

Die eigentliche Generierung der Seite erfolgt zum Schluss mit

$ nikola build

Den lokalen Server startet man mit

$ nikola serve
[2018-10-18T09:57:02Z] INFO: serve: Serving on http://127.0.0.1:8000/ ...

Screenshots

/images/GPlus_plugin/postview.png

Beitragsansicht (Postception!)

/images/GPlus_plugin/archiv.png

Archiv

/images/GPlus_plugin/sharestatus.png

Der Verteilungsstatus ist als Kategorie erfasst

/images/GPlus_plugin/cat_ubersicht.png

Kategorieansicht

Mediaplayer mit GStreamer (Edition gtksink)

Mediaplayer mit GStreamer

Im einführenden Artikel zu Mediaplayer mit GStreamer werden Probleme beschrieben, die auf die Verwendung von "xvimagesink" als Videosink zurückzuführen sind.

In diesem Artikel wird als Alternative der Videosink "gtksink" verwendet und nur auf die Unterschiede zu "xvimagesink" eingegangen, da die weitere Vorgehensweise identisch ist.

Installation

Gtksink war ursprünglich Teil der "bad" plugins, befindet sich aber seit der GStreamer-Version 1.14 in den "good" plugins, die im Normalfall bei der Installation von GStreamer mitinstalliert werden.

Eine Ausnahme bildet Ubuntu, wo das Plugin separat im Paket gstreamer1.0-gtk3 (universe) zur Verfügung steht.

Glade

Der Darstellungsbereich der Mediendatei wird durch das gtksink-eigene Widget bereitgestellt. Da dies nicht in Glade verfügbar ist, wird ein leeres Containerwidget (Gtk.Box) benötigt, in das das Widget platziert werden kann.

Python

Videosink einrichten

self.sink = Gst.ElementFactory.make("gtksink")

Widget einrichten

video_widget = self.sink.get_property("widget")
builder.get_object("video_box").add(video_widget)

Listings

Python

23_gtksink_simpleplayer.py (Source)

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import time

import gi
gi.require_version("Gtk", "3.0")
gi.require_version("Gst", "1.0")
from gi.repository import Gst, Gtk, GLib


class GenericException(Exception):
    pass


class Handler:

    def on_window_destroy(self, *args):
        Gtk.main_quit()

    def on_playpause_togglebutton_toggled(self, widget):
        if app.playpause_button.get_active():
            img = Gtk.Image.new_from_icon_name(Gtk.STOCK_MEDIA_PLAY,
                                               Gtk.IconSize.BUTTON)
            widget.set_property("image", img)
            app.pause()
        else:
            img = Gtk.Image.new_from_icon_name(Gtk.STOCK_MEDIA_PAUSE,
                                               Gtk.IconSize.BUTTON)
            widget.set_property("image", img)
            app.play()

    def on_forward_clicked(self, widget):
        app.skip_time()

    def on_backward_clicked(self, widget):
        app.skip_time(-1)

    def on_progress_value_changed(self, widget):
        app.on_slider_seek

    def on_vbutton_clicked(self, widget):
        app.clear_playbin()
        app.setup_player("mediaplayer.avi")
        if app.playpause_button.get_active() is True:
            app.playpause_button.set_active(False)
        else:
            app.play()

    def on_ibutton_clicked(self, widget):
        app.clear_playbin()
        app.setup_player("mediaplayer.jpg")
        app.pause()


class GstPlayer:

    def __init__(self):

        # init GStreamer
        Gst.init(None)

        # setting up builder
        builder = Gtk.Builder()
        builder.add_from_file("23_gtksink_player.glade")
        builder.connect_signals(Handler())

        #self.movie_window = builder.get_object("play_here")
        self.playpause_button = builder.get_object("playpause_togglebutton")
        self.slider = builder.get_object("progress")
        self.slider_handler_id = self.slider.connect("value-changed", self.on_slider_seek)

        # setting up videoplayer
        self.player = Gst.ElementFactory.make("playbin", "player")
        self.sink = Gst.ElementFactory.make("gtksink")

        # setting up media widget
        video_widget = self.sink.get_property("widget")
        builder.get_object("video_box").add(video_widget)

        window = builder.get_object("window")
        window.show_all()

    def setup_player(self, f):
        # file to play must be transmitted as uri
        uri = "file://" + os.path.abspath(f)
        self.player.set_property("uri", uri)
        self.player.set_property("video-sink", self.sink)

    def play(self):
        self.is_playing = True
        self.player.set_state(Gst.State.PLAYING)
        # starting up a timer to check on the current playback value
        GLib.timeout_add(1000, self.update_slider)

    def pause(self):
        self.is_playing = False
        self.player.set_state(Gst.State.PAUSED)

    def current_position(self):
        status,position = self.player.query_position(Gst.Format.TIME)
        return position

    def skip_time(self, direction=1):
        # skip 20 seconds on forward/backward button
        app.player.seek_simple(Gst.Format.TIME,
                               Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
                               self.current_position() + float(20) * Gst.SECOND * direction,
                               )

    def update_slider(self):
        if not self.is_playing:
            return False # cancel timeout
        else:
            success, self.duration = self.player.query_duration(Gst.Format.TIME)
            # adjust duration and position relative to absolute scale of 100
            self.mult = 100 / (self.duration / Gst.SECOND)
            if not success:
                raise GenericException("Couldn't fetch duration")
            # fetching the position, in nanosecs
            success, position = self.player.query_position(Gst.Format.TIME)
            if not success:
                raise GenericException("Couldn't fetch current position to update slider")

            # block seek handler so we don't seek when we set_value()
            self.slider.handler_block(self.slider_handler_id)
            self.slider.set_value(float(position) / Gst.SECOND * self.mult)
            self.slider.handler_unblock(self.slider_handler_id)
        return True # continue calling every x milliseconds

    def on_slider_seek(self, widget):
        seek_time = app.slider.get_value()
        self.player.seek_simple(Gst.Format.TIME,  Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, seek_time * Gst.SECOND / self.mult)

    def clear_playbin(self):
        try:
            self.player.set_state(Gst.State.NULL)
        except:
            pass

    def main(self):
        Gtk.main()


app = GstPlayer()
app.main()

Glade

23_gtksink_player.glade (Source)

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
  <requires lib="gtk+" version="3.16"/>
  <object class="GtkAdjustment" id="adjustment">
    <property name="upper">100</property>
    <property name="step_increment">1</property>
    <property name="page_increment">10</property>
  </object>
  <object class="GtkImage" id="image1">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="stock">gtk-media-rewind</property>
  </object>
  <object class="GtkImage" id="image2">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="stock">gtk-media-forward</property>
  </object>
  <object class="GtkImage" id="image3">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="stock">gtk-media-pause</property>
  </object>
  <object class="GtkApplicationWindow" id="window">
    <property name="can_focus">False</property>
    <signal name="destroy" handler="on_window_destroy" swapped="no"/>
    <child type="titlebar">
      <object class="GtkHeaderBar">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="show_close_button">True</property>
        <child>
          <object class="GtkButton" id="vbutton">
            <property name="label" translatable="yes">Play video</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <signal name="clicked" handler="on_vbutton_clicked" swapped="no"/>
          </object>
        </child>
        <child>
          <object class="GtkButton" id="ibutton">
            <property name="label" translatable="yes">Show image</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <signal name="clicked" handler="on_ibutton_clicked" swapped="no"/>
          </object>
          <packing>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkBox" id="video_box">
            <property name="height_request">300</property>
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="orientation">vertical</property>
            <child>
              <placeholder/>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkSeparator">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkBox">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkButtonBox">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="layout_style">start</property>
                <child>
                  <object class="GtkButton" id="backward">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="image">image1</property>
                    <property name="always_show_image">True</property>
                    <signal name="clicked" handler="on_backward_clicked" swapped="no"/>
                  </object>
                  <packing>
                    <property name="expand">True</property>
                    <property name="fill">True</property>
                    <property name="position">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkButton" id="forward">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="image">image2</property>
                    <property name="always_show_image">True</property>
                    <signal name="clicked" handler="on_forward_clicked" swapped="no"/>
                  </object>
                  <packing>
                    <property name="expand">True</property>
                    <property name="fill">True</property>
                    <property name="position">1</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkToggleButton" id="playpause_togglebutton">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <property name="image">image3</property>
                    <signal name="toggled" handler="on_playpause_togglebutton_toggled" swapped="no"/>
                  </object>
                  <packing>
                    <property name="expand">True</property>
                    <property name="fill">True</property>
                    <property name="position">2</property>
                  </packing>
                </child>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkScale" id="progress">
                <property name="width_request">300</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="halign">center</property>
                <property name="margin_left">5</property>
                <property name="margin_right">5</property>
                <property name="adjustment">adjustment</property>
                <property name="fill_level">100</property>
                <property name="round_digits">1</property>
                <property name="draw_value">False</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

GNOME-Anwendungsstarter

Anwendungsstarter in GNOME

Anwendungsstarter in GNOME und anderen Desktopumgebungen werden mit Desktopeinträgen in Form von Textdateien mit der Endung "desktop" realisiert.

Speicherort

Der Speicherort von .desktop-Dateien richtet sich nach den Freedesktop-Spezifikationen. Desktop-Dateien befinden sich in $XDG_DATA_DIRS/appications, also normalerweise in den Verzeichnissen

~/.local/share/applications
/usr/local/share/applications
/usr/share/applications

und werden in dieser Reihenfolge durchsucht. Alle Dateien in diesen Verzeichnissen werden in der GNOME-Shell-Übersicht bzw. der Suche berücksichtigt.

Minimalkonfiguration

Ein funktionierender Desktopeintrag muss mindestens die drei folgenden Attribute enthalten:

[Desktop Entry]
Name=Application name
Exec=python path/to/script.py
Type=Application

WM_CLASS

Die WM_CLASS-Eigenschaft wird von X-Windowmanager-Systemen zur Zuordnung zwischen Anwendung und Windowmanager verwendet.

Fehlt diese Zuordnung, wird der Programmname nicht in der Topbar dargestellt, in der Seitenleiste wird das Programm nicht als Instanz angesehen, wenn es als Favorit markiert ist sondern separat und die Anwendung kann nicht von der Übersicht aus als Favorit gespeichert werden.

.desktop

In der Desktopdatei muss das Attribut StartupWMClass definiert werden.

Um die WM_CLASS-Bezeichnung eines Fensters herauszufinden, kann man in einem Terminal

$ xprop | grep WM_CLASS

aufrufen und das gewünschte Fenster anklicken.

Gtk+-Python-Anwendung

Setzt man den Programmnamen mit der Funktion GLib.set_prgname("appname"), so entspricht dies dem Attribut WM_CLASS. In der Desktopdatei muss demzufolge StartupWMClass=appname definiert sein.

Die bisher für diese Aufgabe verwendete Funktion set_wmclass(wmclass_name, wmclass_class) von Gtk.Window ist seit Version 3.22 veraltet. Sie funktioniert zwar noch, sollte aber nicht mehr verwendet werden.

Nützliche Attribute

Path

Arbeitsverzeichnis des Programms. So kann zum Beispiel die Exec-Zeile verkürzt bzw. übersichtlicher gestaltet werden:

# ohne Path
Exec=python /long/path/to/your/application/folder/run.py

# mit Path
Path=/long/path/to/your/application/folder
Exec=python run.py
Icon

Mit Icons verhält es sich ähnlich zu Desktop-Dateien, sie werden zunächst in``$XDG_DATA_DIRS/icons`` vermutet, können aber auch als absoluter Pfad angegeben werden.

Keywords

Da es mit der GNOME-Shell kein klassisches Anwendungsstartermenü mehr gibt, ist es hilfreich, wenn ein Programm unter verschiedenen Stichworten und nicht nur unter Name selbst in der Startersuche gefunden werden kann. Die Stichwörter werden als semikolonseparierte Strings angegeben.

Categories

Hier kann man Kategorien für die Einsortierung in Menüs angeben.

Zusätzliche Programmaktionen

Desktopeinträge können sogenannte Aktionen enthalten, die zusätzliche Wege enthalten, Anwendungen zu starten. Diese werden als Untermenüs in Form von "Quicklists" oder "Jumplists" dargestellt.

Im Desktopeintrag wird das Attribut Actions angelegt, diese Actions werden innerhalb der Datei darunter in "Desktop Action"-Abschnitten definiert:

[Desktop Entry]
...
Actions=option1;option2;

[Desktop Action option1]
Name=Start with Option 1
Exec=python run.py --option1

[Desktop Action option2]
Name=Start with Option 2
Exec=python run.py --option2
/images/desktop_action.png

Zusätzliche Anwendungsstarter von GPT

GPT: v0.5 release

/images/gpt/gpt_icon.png

It has been a while since I have taken some care of my tool to manage my GoPro footage with but it has gotten some attention so I could not just abandon it without losing my face so here we are...

Intro

When I first noticed, without much surprise, that there is no official GoPro desktop client for Linux, I wrote a bash script to automatically rename the files. Second step was converting this into a python script with a simple text based menu. In a weak moment of delusions of grandeur I decided to dive into GUI programming and use this application as my personal guinea pig.

Download

First things first: the result of my efforts can be downloaded from the Git repository:

Bemerkung

If you have cloned the repo sometime in the past and haven't altered anything I recommend to delete and clone again because there may be conflicts caused by a force push because I cannot git.

We've come a long way, baby

Icon

First things first: we have an icon. This is my way of coping with pedantry and an attempt to keep up the illusion of competence. I found it at The Noun Project.

GtkApplication

The application now runs as generic Gtk.Application which includes

  • starting/faving from the GNOME shell

  • identify/kill the process by name (no more random "Python" task)

  • commandline options are available

  • cleaner code, p.e. avoid starting the main loop manually

Application window

Since v0.3 there is a second main application window available with media data information and a preview widget realized with GStreamer.

These two windows are now merged into one providing a StackSwitcher to switch between these alternative views. This now is the default application window.

Not convinced to drop the "single view" windows I decided to keep them for now. You can launch the application using by executing the run script passing one of these options:

$ # compact/list view
$ python run.py -c
$ python run.py --alt-gui-compact
$ # preview window
$ python run.py -e
$ python run.py --alt-gui-ext

If you want to use the old commandline interface, you can do so by running

$ python run.py --cli

Run the script with --help option to show all available options.

Fixed issues

  • importing from "other" places should do as planned now

  • the GStreamer preview now uses the gtksink playbin (this story may be told another time)

  • timelapse generation should not freeze the main loop

Burn the widge(t)

I replaced several widgets for modern looks and better desktop integration:
  • all dialogs are Gtk.MessageDialogs now

  • the dropdown menu is a Gtk.PopoverMenu instead of a Gtk.Menu

Logs and configuration

The output of logging and the configuration file have moved to ~/.config/gpt. You may have to set your working directory again if you have used GPT before.

Installation

Dependencies

That'll do on Archlinux and derivates:

$ sudo pacman -S python-gobject python-yaml python-setuptools python-lxml python-setproctitle mediainfo ffmpeg

And that on Ubuntu:

$ sudo apt-get install python3-gi python3-setuptools python3-lxml gir1.2-gtk-3.0 gir1.2-gstreamer-1.0 gstreamer1.0-gtk3 mediainfo ffmpeg

Setuptools

The application can be installed by using setuptools. After downloading or cloning the repository run

$ python setup.py install --user  # or
$ sudo python setup.py install

Desktop file

Setuptools will also install a desktop file so you can launch GPT from the GNOME shell or menu. All alternative interface options are available via desktop action so you can start these on right click from the activities overview or dash if GPT is running or added as favourite.

/images/gpt/dash_0.5.png

Bits and pieces

  • code improvements (formatting, readability, PEP8 compliance, removal of deprecated code, file structure)

  • updated and detailed README

  • updated localization files

Consult the README for details.

NoN: v0.6 release

Let's just use it as it is now.

The last release was a huge step for the project. Now it's time for some details and polish before I focus on a neglected project of mine.

New feature: upload files to GitHub without deployment

There are two new toolbuttons to push or pull changes to or from GitHub without building or deploying the site. This imitates 'cloud' support so you can edit articles, drafts, listings etc. within the GitHub web interface and/or download/pull changed files on multiple locations.

/images/non/pushdraft06.png

Push files to the origin/src branch

This is a very basic implementation and you may have to manually resolve conflicts if you are editing in various places simultaneously.

Warnung

Consider this feature marked as testing.

Changelog

  • show input file format in statusbar

  • detect if separate metadata file exists and show info in statusbar, open file on right click

  • use the webbrowser Python package instead of subprocess commands; the package also uses the subprocess module but the code just looks nicer

  • the "New post" dialog is a GtkMessageDialog now

  • FileChooserDialog has its OK/Cancel buttons back

  • if the current working directory is bookmarked, the menu entry is labeled as "(active)" and deactivated

  • gettext localization strings in the POT file are now complete

  • German localization is complete

  • some icons changed

/images/non/menu06.png

Menu: open bookmark is deactivated

/images/non/meta06.png

Information about file format and metafile in statusbar, open separate metafile on right click if it exists

The Notwork

Die Nachricht ereilte mich per Twitter: das Ende von Google+ ist besiegelt. Na und? - Das Netzwerk hat doch schon lange seinen Reiz verloren.

Richtiges Netzwerk, falsche Zeit

Als Google im Jahr 2011 sein eigenes soziales Netzwerk launchte, sollte es der Facebook-Killer werden, ohne wie Facebook auszusehen oder zu funktionieren. Dies wirkt zunächst einseitig fokussiert, muss man jedoch bedenken, dass Facebook das mit großem Abstand führende soziale Netzwerk zu dieser Zeit war.

Im deutschsprachigen Raum findet man unter den Top 20 der sozialen Netzwerke neben dem Primus noch die VZ-Netzwerke, Jappy, WerKenntWen und Stayfriends - Netzwerke, die inzwischen heute ein Nischendasein fristen, falls sie noch existieren.

Angesichts der Konkurrenz konnte die Prognose doch gar nicht so schlecht sein? - Wenn da der blaue Riese nicht gewesen wäre. Google erwischte den vielleicht schlechtesten Zeitpunkt zum Launch. Facebook hatte weitgehende Marktbeherrschung und -sättigung (beim Nutzer) errungen. Die Mehrheit war einfach nicht gewillt, aktiv ein weiteres Netzwerk zu nutzen, weil sie schlicht keinen Grund darin sah. Die anhaltende massive Kritik und der Verdruss kamen später.

Die Spielwiese

Wie viele andere habe auch ich schnell Gefallen an Google+ gefunden. Das Kreis-Konzept ermöglichte es, den aktiven wie passiven Gebrauch gruppenbezogen zu filtern. Es gab einen uneingeschränkten Gesamtstream und mit der Ripples-Funktion konnte man den Weg von Beiträgen verfolgen.

Alle drei Elemente hat Google im Laufe der Zeit abgeschafft oder dies zumindest versucht (Kreise wurden nach Protest doch beibehalten, sie waren aber in der mobilen App später standardmäßig nicht aktiviert, allerdings wurde die Kreise teilen-Funktion abgeschafft).

Ideen wie Bildbearbeitungs-Events, echte Gespräche in Kommentarspalten, der Austausch mit vielen unbekannten Leuten und glorreicher Quatsch aller Niveaustufen zeichneten Google+ aus.

GIMPen, bis der Arzt kommt. Mein Beitrag zum Hack My Church - Photomanipulation Contest

Falsch abgebogen

Es war lange Zeit die Rede davon, dass Google+ absolute Priorität im Unternehmen hat. Doch was war nach dem Launch neben der Einführung von Communities und den minimalen Markup-Möglichkeiten eigentlich die letzte positive Entwicklung an Google+? Na? Stimmt, Collections und das Umfragetool waren passende Ergänzungen. Aber sonst?

(Beitrag nicht mehr verfügbar)
Post von vor 5 Jahren: Google hat mal wieder an Plus herumgedoktort

Die Mängelliste ist mit der Zeit stetig gewachsen und als Sahnehäubchen gab es noch den Zwangsaccountverknüpfungs-PR-GAU obendrauf. Mal überlegen, was mir so einfällt:

  • umständliches Kreismanagement, das nie irgendeine Pflege erhielt
  • Fotos:
    • Einschränkung der Bearbeitungsfunktion
    • Alben und Stories (letztere später nicht mehr), Kommentare sprengen einzelne Fotos als Beiträge ab
  • das YouTube/Google+-Kommentarsystem und generell halbseidene Integration
  • Versuch einer Reallnamendurchsetzung
  • "+1"-Empfehlungen
  • Abschaffung von Ripples
  • Abschaffung der Geburtstagsnotiz
  • Unvollständiger "Alles"-Stream
  • Ausklappen der Kommentare in "Facebook-Verhalten", also Anzeige der letzten, nicht aller, Kommentare
  • Buttons sind mal eckig, dann rund und was links ist, wandert nach rechts
  • Speicherhunger der (Android-)App
  • defizitäre Benachrichtigungsfunktion
  • Abschaffung von Community-Managern oder irgendwelchen Ansprechpartnern
  • die merkwürdige Beitragsauswahl des "Angesagten"/"What's hot"-Streams
  • kaputte Streams, plötzlich auftauchende uralte Beiträge
  • Spaces
  • der Mord an Mr. Jingles

Jedes Mal, wenn ein Update für Google+ angekündigt wurde, ging die allgemeine Stimmung in den Keller, man verabschiedete sich im Voraus und selbst die überzeugtesten Atheisten beteten "bitte lass es nicht so schlimm sein".

Diagnose: Stockholm-Syndrom.

Klimawandel

Der Schuldige an der Misere ist gefunden. Google hat es versemmelt. Aber das ist nicht die ganze Wahrheit. Kommen wir zum Elefanten im Raum: der nachlassenden Qualität und thematischen Varianz der Inhalte gefolgt von der Abwanderung der Nutzer gefolgt von nachlassender Interaktion. Teufelskreis.

Was Google+ einmal auszeichnete, war die gute thematische Durchmischung. Es gab einige größere Nachrichtenportale, die eine Präsenz pflegten und in deren Beiträgen man sich austauschen konnte (einfach so, mit fremden Leuten), es gab die Fotografen mit Hashtagterror, Kitschbilder, Musik, Katzen, Fahrräder, Autos, Blümchen, viel schrägen Humor und noch mehr Technik.

Dann fielen zuerst die Nachrichtenseiten aus. Im Allgemeinen gingen diese dazu über, sofern sie es nicht schon von vornherein taten, Google+ als Linkablage mit geschlossenen Kommentaren zu nutzen (manchmal wurde man aufgerufen, etwas zu liken).

Andere, wie etwa der Deutschlandfunk, stellten ihre Aktivität ganz ein und konzentrierten sich auf andere Verbreitungskanäle wie etwa das für eine Hörfunkanstalt sehr viel näher liegende Instagram.

Inhaltlich kippte es von sachlichen, längeren Beiträgen hin zu leicht verdaulicher Screenshot-Kost vorwiegend zu Twitter, etwas Facebook, Klickstrecken, zu komplizierten Sachverhalten wurde allmählich nur noch ein Ja oder Nein geduldet, eine kurzlebige Empörungswelle folgte der nächsten und darüber wurde nie das regelmäßige Virtue Signalling vergessen.

Dafür benötige ich allerdings kein weiteres soziales Netzwerk, das einst durch sein etwas gehobenes Niveau auffiel, denn dann verwende ich nämlich das Original.

Eine Abschiedsnachricht

Bei mir besteht nicht primär die Frage, welche alternativen Plattformen für Google+-Nutzer jetzt in Frage kommen, sondern wohin die bereits abgewanderten ehemaligen Nutzer hin sind und ob diese überhaupt wieder aktivierbar wären.

Denn das Google+, das zum jetzigen Zeitpunkt übrig geblieben ist, möchte ich nicht mehr, auch nicht woanders.

Read on, my dear

Mimicry: make MATE taste like GNOME Shell

GNOME Shell is an elegant desktop environment. I like its appearance, modern looks and the basic concepts of using it. Although I consider myself as a loyal (and/because lazy) user it's not perfect. After testing something in a VM running MATE desktop I realized _how_ laggy it is on my machine. So I decided to trick myself by making MATE behave like GNOME. Does it work?

My GNOME Shell setup

The general desktop experience is given by the GNOME Shell itself but the everyday workflow is determinded by the use of extensions. In fact I state that nobody uses a plain GNOME Shell. So before tweaking the MATE desktop let's take a look at the customizations done to GNOME.

Extensions

Essential

Honorable mentions

... of extensions that don't affect the general workflow

Multi-monitor wallpaper

It's $CURRENT_YEAR and it's still an issue. While you can configure a multi-monitor setup in the preferences conveniently you still have to glue images together with ImageMagick to get different backgrounds on your screens like a caveman.

I highly recommend the application HydraPaper for this task.

Tweaking MATE

Back in the days everybody™ loved GNOME 2. Starting the MATE desktop feels instant familiar.

It's great that the desktop has been completely ported to the GTK+ 3 framework. If you install the MATE packages in addition to GNOME there are hardly dependencies needed for installation. Also regular GNOME applications should fit nicely into the desktop.

Recommended packages and tools:

Getting things to work the GNOME Shell way

Top Panel

Easy one - it's already there and you can have as much panels as you like whereever you want (that includes all screens). Use the regular applets:

  • Weather information is integrated into the clock applet.

  • Battery applet exists but seems to be a little buggy.

  • The TaskBar extension provides the functionality of the good old window list applet, just use the original.

  • The number of workspaces is fixed, use the workspace switcher.

What's on the menu?

You can choose between different menu variations:

Menu Bar:

The classic GNOME 2-like applications menu split into "Applications", "Places" and "System" submenus.

Main Menu:

Condensed classic menu with only the distribution logo (provided by the theme) visible.

Brisk menu:

This menu originated in the Solus project provides an additional search bar. By default this menu is activated by pressing the [Super] key so this may be the choice of a GNOME Shell user.

The Brisk menu is not installed by default. Install the brisk-menu package. Use dconf-editor to change property settings under com.solus-project.brisk-menu. You can enable the dark theme mode or remove the label text.

The displayed icon is determined by the used theme. If you want to use a custom icon you have to copy the chosen icon into the theme's folder as start-here. This may be neccesary for different sizes:

/usr/share/icons/[theme]/places/[size]
~/.local/share/icons/[theme]/places/[size]

The icon for Brisk menu has to be copied as start-here-symbolic in

/usr/share/icons/[theme]/places/symbolic
~/.local/share/icons/[theme]/places/symbolic

You have to press [Esc] to return from the menu instead of hitting [Super] again.

No desktop icons

Who needs icons on the desktop if there are windows in the way anyway? You can disable desktop icons in MATE Tweak or by setting the org.gnome.desktop.background.show-desktop-icons property to "false".

Only show close button in windows

You can get rid of the minimize/maximize buttons by editing the org.mate.Marco.general.button-layout to 'menu:close'.

This solution does not affect applications using a Headerbar.

Dock

There are plenty of options to add application docks on linux desktops. There is also a specific applet for the MATE panel which can be installed by the mate-dock-applet.

My personal recommendation for now is Plank.

Keyboard application launcher

Using a keyboard launcher is one option to emulate the search bar.

With its unobtrusive look and plenty of search options Albert might be the choice of a dedicated GNOME Shell user.

Setting the shortcut to the [Super] key cannot be obtained in Albert's preferences. You will have to create a custom keybinding in dconf-editor:

  1. Go to org.mate.Marco.global-keybindings and set a "run-command-xx" from 'diabled' to 'Super_L'. The "xx" is the number of the command.

  2. Go to org.mate.Marco.keybinding-commands and set the corresponding "command-xx" to the value 'albert show'.

This will overwrite any other keybinding to the specific shortcut like Brisk menu.

Drop down terminal

I used Tilda on the GNOME 2 desktop so why not return to a long-serving application?

Even though the application is set to launch at session start in the preferences I had to add it to the startup applications manually.

/images/mate_or_gnome/mate_tilda.png

Unrolled Tilda terminal on MATE, Plank dock

Multi-monitor setup

The wallpaper issue is the same as in GNOME Shell. You may want to use HydraPaper.

You can drag a panel on an extended screen only if it is not set to "extended" (uncheck in properties).

Marco issues (probably)

  • Dragging a window to another screen might not always set this window in the foreground.

  • Dragging maximized windows (e.g. webbrowser) to other screen may overlay panels.

  • Plugging off and on extended monitors or logging into another session (like GNOME) may disarrange monitor settings and you have to drag the screens back into their positions in the preferences.

Screenshots

If you press [Print] you might be informed that "mate-screenshot" could not be found.

You can either install the mate-utils package which "mate-screenshot" is a part of or use the "gnome-screenshot" tool by editing the dconf entries org.mate.Marco.keybinding-commands.command-screenshot and org.mate.Marco.keybinding-commands.command-window-screenshot to the value gnome-screenshot.

/images/mate_or_gnome/gn_empty.png

Empty GNOME Shell

/images/mate_or_gnome/mate_empty.png

Beware of fraud! This is MATE.

What does not work

Hot corner

The Hot Corner probably is the most symptomatic feature of the GNOME 3 desktop. By moving the mouse to the top left corner or clicking on "Activities" or by pressing the [Super] key you activate the Activities Overview which shows open windows, the dash, workspaces and the application search/launch bar.

This functionality cannot be fully emulated on the MATE desktop.

Using the Brisk menu or a keyboard launcher (or both) to get the search bar function seems like a valid compromise. This is probably the common use case when pressing the [Super] key.

What's still missing is a good way of showing running application windows. I have the habit of kicking the mouse into the corner to get to the windows overview (I realize when doing that occasionally on other desktop systems) and the old [Alt]``+``[Tab] is not a replacement.

/images/mate_or_gnome/gn_win.png

Activities Overview showing open windows

Dynamic workspaces

There is currently no way to get dynamic workspaces with the Marco window manager.

Does it work?

The MATE desktop is a great project. I'm glad that they managed to preserve the GNOME 2 spirit and upgrade it to a modern framework.

It is possible to integrate functionalities known from GNOME Shell into MATE turning it into a fast hybrid GTK+ desktop.

My MATE setup is a GNOME Shell copy. A good one but still. I have not decided yet if I want to live without the hot corner and I'd love to see Marco support headerbars and improved multi-monitor setups.