2012-06-15 8 views
5

Sto usando dynamicLogWithPP da XMonad.Hooks.DynamicLog insieme a dzen2 come barra di stato sotto xmonad. Una delle cose che mi piacerebbe aver visualizzato nella barra è il tempo rimanente nella traccia in riproduzione audace (se presente). Ottenere queste informazioni è semplice:il logHook di xmonad può essere eseguito ad intervalli prestabiliti anziché in (semplicemente) risposta agli eventi di layout?

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 

così posso attaccare che a ppExtras e funziona benissimo — tranne solo viene eseguito quando l'logHook venga eseguito, e che accade solo quando un evento adatto scende il luccio . Pertanto, il display è potenzialmente statico per un lungo periodo di tempo, fino a quando I (ad es.) Commuta gli spazi di lavoro.

Sembra che alcune persone eseguano solo due dozzine di barre, con una uscita in uscita da uno script di shell. È l'unico modo per avere aggiornamenti regolari? Oppure può essere fatto da dentro xmonad (senza diventare troppo pazzo/hacky)?

ETA: ho provato questo, che sembra come se dovrebbe funzionare meglio di quanto non faccia:

  1. creare un Tchan per gli aggiornamenti da XMonad, e un altro per gli aggiornamenti da una funzione di polling Audacious;
  2. impostare il camponella struttura PP da DynamicLog per scrivere sul primo TChan;
  3. forca la funzione di polling audace e fallo scrivere al secondo TChan;
  4. fork una funzione per leggere da entrambi i TChan (verificando che non siano vuoti, prima) e combinando l'output.

Aggiornamenti da XMonad vengono letti dal canale e trattati in modo tempestivo, ma gli aggiornamenti da Audacious sono difficilmente registrati affatto — ogni cinque secondi o giù di lì al meglio. Sembra come se un approccio lungo queste linee dovesse funzionare, però.

+0

Ho aggiornato la mia risposta con un po 'di spiegazioni sul perché la vostra proposta soluzione 'TChan' - e altre basate sull'avere più thread - non funziona correttamente. –

+0

Grazie per l'aggiornamento. –

risposta

6

So che questa è una vecchia domanda, ma sono venuto qui cercando una risposta a questo qualche giorno fa, e ho pensato di condividere il modo in cui l'ho risolto. In realtà puoi farlo interamente da xmonad. È un po 'hacky, ma penso che sia molto più bello di tutte le alternative che ho incontrato.

Fondamentalmente, ho utilizzato la libreria XMonad.Util.Timer, che invierà un evento X dopo un periodo di tempo specificato (in questo caso, un secondo).Quindi ho appena scritto un hook di eventi per questo, che riavvia il timer e quindi esegue manualmente il hook del log.

Ho anche dovuto utilizzare la libreria XMonad.Util.ExtensibleState, perché Timer utilizza una variabile id per assicurarsi che risponda all'evento giusto, quindi devo memorizzare quella variabile tra gli eventi.

Ecco il mio codice:

{-# 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 

piuttosto semplice. Spero che questo sia utile a qualcuno.

+0

Per chiunque altro usi questo codice, devi anche importare Data.Monoid' – user316146

+0

Questo rompe la possibilità di riavviare xmonad per me: sto assumendo che il processo riavviato non possa gestire eventi dal vecchio processo (non sono sicuro come sopravviveranno il processo si riavvia però). Ho dovuto estenderlo per interrompere l'attivazione quando è stato avviato lo spegnimento e attendere fino a quando l'ultimo evento è stato gestito durante l'arresto. – akosch

+0

@akosch Oh wow, ho dimenticato questa domanda. Sì, mi impedisce anche di essere in grado di riavviare, e ho cambiato la mia configurazione personale da quando ho postato questa risposta. Oggigiorno ho un'istanza Conky che invia un evento X a xmonad una volta al secondo. L'evento contiene informazioni sull'hardware, che visualizzo anche in dozzina, ma il punto è che sto usando un programma esterno per avviare l'aggiornamento ora. Ma se hai funzionato con riavvii, forse la risposta dovrebbe essere aggiornata con il tuo codice? – DarthFennec

2

Non può essere eseguito da xmonad; l'attuale modello di threading di xmonad è un po 'carente (e lo è anche quello di dzen). Tuttavia, è possibile avviare un processo separato che esegue periodicamente il polling del lettore musicale e quindi utilizzare uno dei multiplexer dzen (ad esempio dmplex) per combinare l'output dei due processi.

Si potrebbe anche voler guardare in xmobar e taffybar, che hanno entrambi storie di threading migliori di dzen fa.

Per quanto riguarda il motivo per cui il proposto TChan soluzione non funziona correttamente, si potrebbe desiderare di leggere le sezioni "convenzioni", "importazioni straniere", e "The Non-Threaded Runtime" a my crash course on the FFI and gtk, tenendo presente che xmonad attualmente utilizza il runtime non-threaded di GHC. La risposta breve è che il ciclo principale di xmonad effettua una chiamata FFI a Xlib che attende un evento X; questa chiamata blocca tutti gli altri thread Haskell da eseguire finché non ritorna.