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

150 lines
4.4 KiB
Haskell
Raw Normal View History

2020-05-28 23:17:17 -04:00
--------------------------------------------------------------------------------
2022-12-30 14:58:23 -05:00
-- Device plugin
2020-05-28 23:17:17 -04:00
--
-- Display different text depending on whether or not the interface has
-- connectivity
2022-07-09 17:08:10 -04:00
module Xmobar.Plugins.Device
2022-12-30 14:58:23 -05:00
( Device (..)
2022-07-09 17:08:10 -04:00
, devDep
2022-12-30 14:58:23 -05:00
)
where
import DBus
import Data.Internal.DBus
2023-01-01 18:33:02 -05:00
import Data.Internal.XIO
2022-12-30 16:59:50 -05:00
import RIO
2023-09-30 18:51:07 -04:00
import qualified RIO.Map as M
import qualified RIO.NonEmpty as NE
2022-12-30 14:58:23 -05:00
import qualified RIO.Text as T
import XMonad.Internal.Command.Desktop
import XMonad.Internal.DBus.Common
import Xmobar
import Xmobar.Plugins.Common
2021-11-25 00:12:00 -05:00
2023-09-30 18:51:07 -04:00
newtype Device = Device (NE.NonEmpty T.Text, T.Text, Colors) deriving (Read, Show)
2021-11-25 00:12:00 -05:00
nmPath :: ObjectPath
nmPath = objectPath_ "/org/freedesktop/NetworkManager"
2020-05-28 23:17:17 -04:00
2021-11-25 00:12:00 -05:00
nmInterface :: InterfaceName
nmInterface = interfaceName_ "org.freedesktop.NetworkManager"
2023-09-30 18:51:07 -04:00
nmActiveInterface :: InterfaceName
nmActiveInterface =
interfaceName_ "org.freedesktop.NetworkManager.Connection.Active"
stateChanged :: MemberName
stateChanged = "StateChanged"
2020-05-28 23:17:17 -04:00
2021-11-25 00:12:00 -05:00
getByIP :: MemberName
getByIP = memberName_ "GetDeviceByIpIface"
2022-07-09 17:08:10 -04:00
devDep :: DBusDependency_ SysClient
2022-12-30 14:58:23 -05:00
devDep =
Endpoint networkManagerPkgs networkManagerBus nmPath nmInterface $
Method_ getByIP
2023-09-30 18:51:07 -04:00
-- -- TODO not DRY, make a NM specific section somewhere for this call
ethBus :: BusName
ethBus = busName_ "org.freedesktop.NetworkManager"
data EthEnv c = EthEnv
{ ethClient :: !c
, ethState :: !(MVar EthState)
, ethDisplay :: !(EthIO ())
, ethEnv :: !SimpleApp
}
instance HasLogFunc (EthEnv c) where
logFuncL = lens ethEnv (\x y -> x {ethEnv = y}) . logFuncL
instance HasClient EthEnv where
clientL = lens ethClient (\x y -> x {ethClient = y})
type EthIO = RIO (EthEnv SysClient)
type EthState = M.Map ObjectPath T.Text
getConnectionProp :: MemberName -> ObjectPath -> EthIO [Variant]
getConnectionProp prop path = callPropertyGet ethBus path nmActiveInterface prop
getConnectionId :: ObjectPath -> EthIO (Maybe T.Text)
getConnectionId = fmap fromSingletonVariant . getConnectionProp "Id"
getConnectionType :: ObjectPath -> EthIO (Maybe T.Text)
getConnectionType = fmap fromSingletonVariant . getConnectionProp "Type"
updateConnected :: NE.NonEmpty T.Text -> ObjectPath -> EthIO ()
updateConnected contypes path = do
typeRes <- getConnectionType path
case typeRes of
Nothing -> logError "could not get type"
Just contype -> do
when (contype `elem` contypes) $ do
idRes <- getConnectionId path
case idRes of
Nothing -> logError "could not get ID"
Just i -> do
s <- asks ethState
modifyMVar_ s $ return . M.insert path i
updateDisconnected :: ObjectPath -> EthIO ()
updateDisconnected path = do
s <- asks ethState
modifyMVar_ s $ return . M.delete path
testActiveType :: NE.NonEmpty T.Text -> Signal -> EthIO ()
testActiveType contypes sig = do
dpy <- asks ethDisplay
case signalBody sig of
[state, _] -> case fromVariant state of
Just (2 :: Word32) -> updateConnected contypes path >> dpy
Just 4 -> updateDisconnected path >> dpy
_ -> return ()
_ -> return ()
2021-11-25 00:12:00 -05:00
where
2023-09-30 18:51:07 -04:00
path = signalPath sig
2021-11-25 00:12:00 -05:00
2023-09-30 18:51:07 -04:00
initialState
2023-01-03 22:18:55 -05:00
:: ( SafeClient c
2023-09-30 18:51:07 -04:00
, MonadUnliftIO m
2023-01-03 22:18:55 -05:00
, MonadReader (env c) m
2023-09-30 18:51:07 -04:00
, HasClient env
2023-01-03 22:18:55 -05:00
, HasLogFunc (env c)
)
2023-09-30 18:51:07 -04:00
=> NE.NonEmpty T.Text
-> m EthState
initialState contypes =
M.mapMaybe go <$> callGetManagedObjects ethBus "/org/freedesktop"
where
go = getId <=< M.lookup nmActiveInterface
getId m =
fromVariant
=<< (\t -> if t `elem` contypes then M.lookup "Id" m else Nothing)
=<< fromVariant
=<< M.lookup "Type" m
2021-11-25 00:12:00 -05:00
2023-09-30 18:51:07 -04:00
readState :: EthIO [T.Text]
readState = M.elems <$> (readMVar =<< asks ethState)
2020-05-28 23:17:17 -04:00
instance Exec Device where
2023-09-30 18:51:07 -04:00
alias (Device (_, _, _)) = "connection"
start (Device (contypes, text, colors)) cb =
withDBusClientConnection cb (Just "ethernet.log") $ \c -> do
let dpy = displayMaybe cb formatter . Just =<< readState
i <- withDIO c $ initialState contypes
s <- newMVar i
mapRIO (EthEnv c s dpy) $ do
addListener
dpy
2020-05-28 23:17:17 -04:00
where
2023-09-30 18:51:07 -04:00
formatter names = return $ case names of
[] -> colorText colors False text
xs -> T.unwords [T.intercalate "|" xs, colorText colors True text]
addListener = do
res <- matchSignalFull ethBus Nothing (Just nmActiveInterface) (Just stateChanged)
2023-01-01 22:40:28 -05:00
case res of
2023-09-30 18:51:07 -04:00
Just rule -> void $ addMatchCallbackSignal rule (testActiveType contypes)
2023-01-01 22:40:28 -05:00
Nothing -> logError "could not start listener"