2012-06-15 7 views
5

Ich verwende dynamicLogWithPP von XMonad.Hooks.DynamicLog zusammen mit dzen2 als Statusleiste unter Xmonad. Eines der Dinge, die ich gerne in der Leiste anzeigen würde, ist die Zeit, die in dem aktuell spielenden Track in kühnen (falls vorhanden) verbleibt. diese Informationen zu erhalten ist einfach:Kann das LogHook von xmonad in festgelegten Intervallen ausgeführt werden und nicht nur als Reaktion auf Layout-Ereignisse?

audStatus :: Player -> X (Maybe String) 
audStatus p = do 
    info <- liftIO $ tryS $ withPlayer p $ do 
       ispaused <- paused 
       md <- getMetadataString 
       timeleftmillis <- (-) <$> (getCurrentTrack >>= songFrames) <*> time 
       let artist = md ! "artist" 
        title = md ! "title" 
        timeleft = timeleftmillis `quot` 1000 
        (minutes, seconds) = timeleft `quotRem` 60 
        disp = artist ++ " - " ++ title ++ " (-"++(show minutes)++":"++(show seconds)++")" -- will be wrong if seconds < 10 
        audcolor False = dzenColor base0 base03 
        audcolor True = dzenColor base1 base02 
       return $ wrap "^ca(1, pms p)" "^ca()" (audcolor ispaused disp) 
    return $ either (const Nothing) Just info 

So kann ich das in ppExtras halten und es funktioniert gut — außer es wird nur ausgeführt, wenn die logHook fuehrt wird, und das geschieht nur, wenn eine geeignete Veranstaltung auf den Hecht kommt . Daher ist die Anzeige möglicherweise für eine lange Zeit möglicherweise statisch, bis ich (z. B.) Arbeitsbereiche umschalte.

Es sieht so aus, als würden einige Leute nur zwei Dutzend Bars laufen lassen, wobei eine Ausgabe von einem Shell-Skript weitergeleitet wird. Ist das die einzige Möglichkeit, regelmäßige Updates zu haben? Oder kann dies innerhalb von xmonad getan werden (ohne zu verrückt/hacky zu werden)?

ETA: Ich habe versucht, das, was scheint, als ob es sollte besser funktionieren, als es:

  1. eine Tchan für Updates von XMonad erstellen, und eine andere für Updates von einer Funktion Polling Audacious;
  2. setzen Sie das ppOutput Feld in der Struktur von DynamicLog, um zum ersten TChan zu schreiben;
  3. fork die kühnen-polling-funktion und haben es schreiben auf die zweite TChan;
  4. Fork eine Funktion zum Lesen von beiden TChans (Überprüfung, dass sie nicht leer sind, zuerst), und die Kombination der Ausgabe.

Updates von XMonad werden aus dem Kanal gelesen und in einer angemessenen Art und Weise verarbeitet, aber Updates von Audacious sind so gut wie gar — alle fünf oder so Sekunden bestenfalls registriert. Es scheint, als ob ein Ansatz in dieser Richtung funktionieren müsste.

+0

Ich habe meine Antwort mit ein wenig Erklärung darüber, warum Ihre vorgeschlagene "TChan" -Lösung - und andere basierend auf mehreren Threads - nicht richtig funktioniert. –

+0

Danke für das Update. –

Antwort

6

Ich weiß, das ist eine alte Frage, aber ich bin hier hergekommen, um vor ein paar Tagen nach einer Antwort zu suchen, und ich dachte, ich würde teilen, wie ich es gelöst habe. Sie können es tatsächlich vollständig von xmonad tun. Es ist ein bisschen hacky, aber ich denke, es ist viel schöner als jede der Alternativen, die ich gefunden habe.

Grundsätzlich habe ich die XMonad.Util.Timer-Bibliothek verwendet, die nach einer bestimmten Zeitspanne (in diesem Fall eine Sekunde) ein X-Ereignis senden wird.Dann habe ich einfach einen Ereignis-Hook dafür geschrieben, der den Timer erneut startet und dann den Log-Hook manuell startet.

Ich musste auch die XMonad.Util.ExtensibleState-Bibliothek verwenden, weil Timer eine ID-Variable verwendet, um sicherzustellen, dass es auf das richtige Ereignis reagiert, also muss ich diese Variable zwischen den Ereignissen speichern.

Hier ist mein Code:

{-# LANGUAGE DeriveDataTypeable #-} 

import qualified XMonad.Util.ExtensibleState as XS 
import XMonad.Util.Timer 

... 

-- wrapper for the Timer id, so it can be stored as custom mutable state 
data TidState = TID TimerId deriving Typeable 

instance ExtensionClass TidState where 
    initialValue = TID 0 

... 

-- put this in your startupHook 
-- start the initial timer, store its id 
clockStartupHook = startTimer 1 >>= XS.put . TID 

-- put this in your handleEventHook 
clockEventHook e = do    -- e is the event we've hooked 
    (TID t) <- XS.get     -- get the recent Timer id 
    handleTimer t e $ do    -- run the following if e matches the id 
    startTimer 1 >>= XS.put . TID -- restart the timer, store the new id 
    ask >>= logHook.config   -- get the loghook and run it 
    return Nothing     -- return required type 
    return $ All True     -- return required type 

ziemlich einfach. Ich hoffe, das ist hilfreich für jemanden.

+0

Für alle anderen, die diesen Code verwenden, müssen Sie auch 'Import.Monoid' importieren. – user316146

+0

Das bricht die Fähigkeit, xmonad für mich neu zu starten: Ich nehme an, der neu gestartete Prozess kann nicht mit Ereignissen aus dem alten Prozess umgehen (nicht sicher, wie diese überleben der Prozessneustart aber). Ich musste es verlängern, um zu beenden, wenn der Shutdown eingeleitet wurde, und warten, bis das letzte Ereignis beim Herunterfahren behandelt wurde. – akosch

+0

@akosch Oh wow, ich habe diese Frage vergessen. Ja, es hält mich auch davon ab, neu starten zu können, und ich habe mein persönliches Setup geändert, seit ich diese Antwort gepostet habe. Heutzutage habe ich eine Conky-Instanz, die einmal pro Sekunde ein X-Event an xmonad sendet. Das Ereignis enthält Hardware-Informationen, die ich auch in dzen anzeigen kann, aber der Punkt ist, dass ich ein externes Programm verwende, um das Update jetzt auszulösen. Aber wenn Sie mit Neustarts arbeiten, sollte die Antwort vielleicht mit Ihrem Code aktualisiert werden? – DarthFennec

2

Es kann nicht innerhalb von xmonad; Das aktuelle Threading-Modell von xmonad fehlt etwas (und auch das von dzen). Sie können jedoch einen separaten Prozess starten, der regelmäßig Ihren Musikplayer abfragt und dann einen der dzen-Multiplexer (z. B. dmplex) verwendet, um die Ausgabe der beiden Prozesse zu kombinieren.

Sie können auch in xmobar und taffybar suchen, die beide bessere Threading Geschichten als dzen haben.

In Bezug auf, warum Ihr Vorschlag TChan Lösung funktioniert nicht richtig, könnte man die Abschnitte „Conventions“, „Foreign Imports“ und „The Non-Threaded Runtime“ bei my crash course on the FFI and gtk, unter Berücksichtigung der Tatsache lesen möchten, die xmonad verwendet derzeit die GHF-Laufzeit ohne Threads. Die kurze Antwort ist, dass die Hauptschleife von xmonad einen FFI-Aufruf an Xlib macht, der auf ein X-Ereignis wartet; Dieser Aufruf blockiert alle anderen Haskell-Threads von der Ausführung bis zur Rückgabe.