xmonad-config/lib/Xmobar/Plugins/Common.hs

141 lines
4.3 KiB
Haskell
Raw Normal View History

module Xmobar.Plugins.Common
2021-11-27 17:33:02 -05:00
( colorText
2021-11-24 01:14:23 -05:00
, startListener
, procSignalMatch
2021-11-25 00:12:00 -05:00
, na
, fromSingletonVariant
2023-10-15 21:50:46 -04:00
, withNestedDBusClientConnection
, withDBusClientConnection
, Callback
2022-12-30 14:58:23 -05:00
, Colors (..)
2021-11-27 13:24:13 -05:00
, displayMaybe
, displayMaybe'
2021-11-27 17:33:02 -05:00
, xmobarFGColor
2023-10-01 00:24:33 -04:00
, PluginEnv (..)
, PluginIO
2023-10-01 01:02:06 -04:00
, pluginDisplay
2021-11-24 01:14:23 -05:00
)
2022-12-30 14:58:23 -05:00
where
2022-12-30 14:58:23 -05:00
import DBus
import DBus.Client
import Data.Internal.DBus
2023-01-03 23:33:08 -05:00
import Data.Internal.XIO
import RIO
2022-12-30 14:58:23 -05:00
import qualified RIO.Text as T
import XMonad.Hooks.DynamicLog (xmobarColor)
2021-11-24 01:14:23 -05:00
2023-10-01 00:24:33 -04:00
data PluginEnv s c = PluginEnv
2023-10-27 23:12:22 -04:00
{ plugClient :: !(NamedConnection c)
2023-10-01 00:24:33 -04:00
, plugState :: !(MVar s)
2023-10-01 01:02:06 -04:00
, plugDisplay :: !(Callback -> PluginIO s c ())
, plugCallback :: !Callback
2023-10-01 00:24:33 -04:00
, plugEnv :: !SimpleApp
}
2023-10-01 01:02:06 -04:00
pluginDisplay :: PluginIO s c ()
pluginDisplay = do
cb <- asks plugCallback
dpy <- asks plugDisplay
dpy cb
2023-10-01 00:24:33 -04:00
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 ()
2021-11-27 17:33:02 -05:00
data Colors = Colors
2022-12-30 14:58:23 -05:00
{ colorsOn :: T.Text
, colorsOff :: T.Text
2021-11-27 17:33:02 -05:00
}
deriving (Eq, Show, Read)
2022-12-30 14:58:23 -05:00
startListener
2023-02-12 23:08:05 -05:00
:: ( HasClient env
2023-01-03 22:18:55 -05:00
, MonadReader (env c) m
, MonadUnliftIO m
, SafeClient c
, IsVariant a
)
2022-12-30 14:58:23 -05:00
=> MatchRule
2023-01-03 22:18:55 -05:00
-> m [Variant]
2022-12-30 14:58:23 -05:00
-> ([Variant] -> SignalMatch a)
-> (a -> m T.Text)
2022-12-30 14:58:23 -05:00
-> Callback
-> m ()
2023-01-03 22:18:55 -05:00
startListener rule getProp fromSignal toColor cb = do
reply <- getProp
displayMaybe cb toColor $ fromSingletonVariant reply
2023-01-03 22:18:55 -05:00
void $ addMatchCallback rule (procMatch . fromSignal)
2021-11-24 01:14:23 -05:00
where
procMatch = procSignalMatch cb toColor
procSignalMatch
:: MonadUnliftIO m => Callback -> (a -> m T.Text) -> SignalMatch a -> m ()
2021-11-27 13:24:13 -05:00
procSignalMatch cb f = withSignalMatch (displayMaybe cb f)
colorText :: Colors -> Bool -> T.Text -> T.Text
2022-12-30 14:58:23 -05:00
colorText Colors {colorsOn = c} True = xmobarFGColor c
colorText Colors {colorsOff = c} False = xmobarFGColor c
2021-11-27 17:33:02 -05:00
xmobarFGColor :: T.Text -> T.Text -> T.Text
xmobarFGColor c = T.pack . xmobarColor (T.unpack c) "" . T.unpack
2021-11-25 00:12:00 -05:00
na :: T.Text
2021-11-25 00:12:00 -05:00
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
2021-11-27 13:24:13 -05:00
displayMaybe' :: MonadUnliftIO m => Callback -> (a -> m ()) -> Maybe a -> m ()
displayMaybe' cb = maybe (liftIO $ cb $ T.unpack na)
withDBusClientConnection
:: (MonadUnliftIO m, SafeClient c)
=> Callback
2023-10-27 23:12:22 -04:00
-> Maybe BusName
2023-01-03 23:33:08 -05:00
-> Maybe FilePath
2023-10-27 23:12:22 -04:00
-> (NamedConnection c -> RIO SimpleApp ())
-> m ()
2023-10-27 23:12:22 -04:00
withDBusClientConnection cb n logfile f =
2023-01-03 23:33:08 -05:00
maybe (run stderr) (`withLogFile` run) logfile
2023-01-01 22:29:29 -05:00
where
2023-01-03 23:33:08 -05:00
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 n
2023-10-15 21:50:46 -04:00
2023-10-28 00:18:33 -04:00
-- | Run a plugin action with a new DBus client and logfile path. This is
-- necessary for DBus callbacks which run in separate threads, which will
-- usually fire when the parent thread already exited and killed off its DBus
-- connection and closed its logfile. NOTE: unlike 'withDBusClientConnection'
-- this function will open and new logfile and client connection and close both
-- on completion. 'withDBusClientConnection' will only close the log file but
-- keep the client connection active upon termination; this client will only be
-- killed when the entire process is killed. This distinction is important
-- because callbacks only need ephemeral connections, while listeners (started
-- with 'withDBusClientConnection') need long-lasting connections.
2023-10-15 21:50:46 -04:00
withNestedDBusClientConnection
:: (MonadUnliftIO m, SafeClient c, MonadReader (PluginEnv s c) m)
2023-10-27 23:12:22 -04:00
=> Maybe BusName
-> Maybe FilePath
2023-10-15 21:50:46 -04:00
-> PluginIO s c ()
-> m ()
2023-10-27 23:12:22 -04:00
withNestedDBusClientConnection n logfile f = do
2023-10-15 21:50:46 -04:00
dpy <- asks plugDisplay
s <- asks plugState
cb <- asks plugCallback
let run h = do
logOpts <- setLogVerboseFormat True . setLogUseTime True <$> logOptionsHandle h False
withLogFunc logOpts $ \lf -> do
env <- mkSimpleApp lf Nothing
runRIO env $ withDBusClient_ n $ \cl -> mapRIO (PluginEnv cl s dpy cb) f
maybe (run stderr) (`withLogFile` run) logfile