module Xmobar.Plugins.Common ( colorText , startListener , procSignalMatch , na , fromSingletonVariant , withDBusClientConnection , Callback , Colors (..) , displayMaybe , displayMaybe' , xmobarFGColor , PluginEnv (..) , PluginIO , pluginDisplay ) where import DBus import DBus.Client import Data.Internal.DBus import Data.Internal.XIO import RIO import qualified RIO.Text as T import XMonad.Hooks.DynamicLog (xmobarColor) data PluginEnv s c = PluginEnv { plugClient :: !c , plugState :: !(MVar s) , plugDisplay :: !(Callback -> PluginIO s c ()) , plugCallback :: !Callback , plugEnv :: !SimpleApp } pluginDisplay :: PluginIO s c () pluginDisplay = do cb <- asks plugCallback dpy <- asks plugDisplay dpy cb type PluginIO s c = RIO (PluginEnv s c) instance HasClient (PluginEnv s) where clientL = lens plugClient (\x y -> x {plugClient = y}) instance HasLogFunc (PluginEnv s c) where logFuncL = lens plugEnv (\x y -> x {plugEnv = y}) . logFuncL -- use string here since all the callbacks in xmobar use strings :( type Callback = String -> IO () data Colors = Colors { colorsOn :: T.Text , colorsOff :: T.Text } deriving (Eq, Show, Read) startListener :: ( HasClient env , MonadReader (env c) m , MonadUnliftIO m , SafeClient c , IsVariant a ) => MatchRule -> m [Variant] -> ([Variant] -> SignalMatch a) -> (a -> m T.Text) -> Callback -> m () startListener rule getProp fromSignal toColor cb = do reply <- getProp displayMaybe cb toColor $ fromSingletonVariant reply void $ addMatchCallback rule (procMatch . fromSignal) where procMatch = procSignalMatch cb toColor procSignalMatch :: MonadUnliftIO m => Callback -> (a -> m T.Text) -> SignalMatch a -> m () procSignalMatch cb f = withSignalMatch (displayMaybe cb f) colorText :: Colors -> Bool -> T.Text -> T.Text colorText Colors {colorsOn = c} True = xmobarFGColor c colorText Colors {colorsOff = c} False = xmobarFGColor c xmobarFGColor :: T.Text -> T.Text -> T.Text xmobarFGColor c = T.pack . xmobarColor (T.unpack c) "" . T.unpack na :: T.Text na = "N/A" displayMaybe :: MonadUnliftIO m => Callback -> (a -> m T.Text) -> Maybe a -> m () displayMaybe cb f = (liftIO . cb . T.unpack) <=< maybe (return na) f displayMaybe' :: MonadUnliftIO m => Callback -> (a -> m ()) -> Maybe a -> m () displayMaybe' cb = maybe (liftIO $ cb $ T.unpack na) withDBusClientConnection :: (MonadUnliftIO m, SafeClient c) => Callback -> Maybe FilePath -> (c -> RIO SimpleApp ()) -> m () withDBusClientConnection cb logfile f = maybe (run stderr) (`withLogFile` run) logfile where run h = do logOpts <- setLogVerboseFormat True . setLogUseTime True <$> logOptionsHandle h False withLogFunc logOpts $ \lf -> do env <- mkSimpleApp lf Nothing runRIO env $ displayMaybe' cb f =<< getDBusClient