2012-06-15 14 views
5

Estoy usando dynamicLogWithPP desde XMonad.Hooks.DynamicLog junto con dzen2 como una barra de estado bajo xmonad. Una de las cosas que me gustaría que se muestre en la barra es el tiempo restante en la pista que se está reproduciendo en audaz (si existe). Obtener esta información es fácil:¿se puede ejecutar logHook de xmonad en intervalos establecidos en lugar de en (meramente) responder a eventos de diseño?

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 

Así que puede pegarse de que en ppExtras y funciona bien — excepto que sólo se ejecute cuando el logHook se ejecute, y que sólo ocurre cuando un evento adecuado llega pronto al mercado . Por lo tanto, la pantalla es potencialmente estática durante un tiempo prolongado, hasta que yo (por ejemplo) cambie de espacio de trabajo.

Parece que algunas personas solo ejecutan dos barras de dzen, y una obtiene la salida de un script de shell. ¿Es esa la única forma de tener actualizaciones regulares? ¿O puede hacerse desde dentro de xmonad (sin volverse demasiado loco/hacky)?

ETA: He intentado esto, que parece como si debería funcionar mejor de lo que lo hace:

  1. crear un TCHAN para recibir actualizaciones de xmonad, y otro para las actualizaciones de un sondeo de la función audaz;
  2. establece el campo ppOutput en la estructura PP desde DynamicLog para escribir en el primer TChan;
  3. bifurque la audaz función de sondeo y pídales que escriban en el segundo TChan;
  4. fork una función para leer desde ambos TChans (verificando que no estén vacíos, primero) y combinar la salida.

actualizaciones de xmonad se leen desde el canal y se procesa en el momento oportuno, pero las actualizaciones de audaz apenas están registrados en absoluto — cada cinco segundos más o menos en el mejor. Sin embargo, parece que algún enfoque en esta línea debería funcionar.

+0

He actualizado mi respuesta con un poco de explicación acerca de por qué su solución 'TChan' propuesta, y otras basadas en tener varios hilos, no funciona correctamente. –

+0

Gracias por la actualización. –

Respuesta

6

Sé que esta es una vieja pregunta, pero vine aquí buscando una respuesta a esto hace unos días, y pensé que compartiría la forma en que lo resolví. En realidad puedes hacerlo completamente desde xmonad. Es un poco hacky, pero creo que es mucho mejor que cualquiera de las alternativas que he encontrado.

Básicamente, utilicé la biblioteca XMonad.Util.Timer, que enviará un evento X después de un período de tiempo especificado (en este caso, un segundo).Luego, escribí un gancho de evento para él, que inicia el temporizador de nuevo y luego ejecuta manualmente el enlace de registro.

También tuve que usar la biblioteca XMonad.Util.ExtensibleState, porque Timer utiliza una variable de id para asegurarse de que está respondiendo al evento correcto, así que tengo que almacenar esa variable entre eventos.

Aquí está mi código:

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

bastante sencillo. Espero que esto sea útil para alguien.

+0

Para cualquier otra persona que use este código, también debe 'importar Data.Monoid' – user316146

+0

Esto interrumpe la capacidad de reiniciar xmonad para mí: asumo que el proceso reiniciado no puede manejar eventos del proceso anterior (no estoy seguro de cómo sobreviven) el proceso de reinicio sin embargo). Tuve que extenderlo para dejar de disparar cuando se inició el apagado y esperar hasta que se haya manejado el último evento durante el apagado. – akosch

+0

@akosch Oh wow, me olvidé de esta pregunta. Sí, también evita que pueda reiniciar, y he cambiado mi configuración personal desde que publiqué esta respuesta. Actualmente tengo una instancia de Conky enviando un evento X a xmonad una vez por segundo. El evento contiene información de hardware, que también muestro en dzen, pero el punto es que estoy usando un programa externo para activar la actualización ahora. Pero si lo hiciste trabajando con reinicios, ¿tal vez la respuesta debería actualizarse con tu código? – DarthFennec

2

No se puede hacer desde dentro de xmonad; El modelo actual de subprocesamiento de xmonad es un poco inexistente (y también lo es el de Dzen). Sin embargo, puede iniciar un proceso separado que sondee periódicamente su reproductor de música y luego use uno de los multiplexores dzen (por ejemplo, dmplex) para combinar la salida de los dos procesos.

Es posible que también desee consultar xmobar y taffybar, que tienen mejores historias de enhebrado que dzen.

En cuanto a por qué su solución TChan propuesta no funciona correctamente, es posible que desee leer las secciones "convenciones", "las importaciones extranjeras", y "El tiempo de ejecución sin rosca" en my crash course on the FFI and gtk, teniendo en cuenta que xmonad actualmente usa el tiempo de ejecución no roscado de GHC. La respuesta corta es que el bucle principal de xmonad hace una llamada FFI a Xlib que espera un evento X; esta llamada impide que todos los demás hilos Haskell se ejecuten hasta que vuelva.

Cuestiones relacionadas