module System.Taffybar.Battery (
batteryBarNew,
textBatteryNew,
defaultBatteryConfig
) where
import qualified Control.Exception.Enclosed as E
import Data.Int ( Int64 )
import Data.IORef
import Graphics.UI.Gtk
import qualified System.IO as IO
import Text.Printf ( printf )
import Text.StringTemplate
import System.Information.Battery
import System.Taffybar.Widgets.PollingBar
import System.Taffybar.Widgets.PollingLabel
safeGetBatteryInfo :: IORef BatteryContext -> IO (Maybe BatteryInfo)
safeGetBatteryInfo mv = do
ctxt <- readIORef mv
E.catchAny (getBatteryInfo ctxt) $ \_ -> reconnect
where
reconnect = do
mctxt <- batteryContextNew
case mctxt of
Nothing -> IO.hPutStrLn IO.stderr "Could not reconnect to UPower"
Just ctxt -> writeIORef mv ctxt
return Nothing
battInfo :: IORef BatteryContext -> String -> IO String
battInfo r fmt = do
minfo <- safeGetBatteryInfo r
case minfo of
Nothing -> return ""
Just info -> do
let battPctNum :: Int
battPctNum = floor (batteryPercentage info)
formatTime :: Int64 -> String
formatTime seconds =
let minutes = seconds `div` 60
hours = minutes `div` 60
minutes' = minutes `mod` 60
in printf "%02d:%02d" hours minutes'
battTime :: String
battTime = case (batteryState info) of
BatteryStateCharging -> (formatTime $ batteryTimeToFull info)
BatteryStateDischarging -> (formatTime $ batteryTimeToEmpty info)
_ -> "-"
tpl = newSTMP fmt
tpl' = setManyAttrib [ ("percentage", show battPctNum)
, ("time", battTime)
] tpl
return $ render tpl'
textBatteryNew :: String
-> Double
-> IO Widget
textBatteryNew fmt pollSeconds = do
battCtxt <- batteryContextNew
case battCtxt of
Nothing -> do
let lbl :: Maybe String
lbl = Just "No battery"
labelNew lbl >>= return . toWidget
Just ctxt -> do
r <- newIORef ctxt
l <- pollingLabelNew "" pollSeconds (battInfo r fmt)
widgetShowAll l
return l
battPct :: IORef BatteryContext -> IO Double
battPct r = do
minfo <- safeGetBatteryInfo r
case minfo of
Nothing -> return 0
Just info -> return (batteryPercentage info / 100)
defaultBatteryConfig :: BarConfig
defaultBatteryConfig =
defaultBarConfig colorFunc
where
colorFunc pct
| pct < 0.1 = (1, 0, 0)
| pct < 0.9 = (0.5, 0.5, 0.5)
| otherwise = (0, 1, 0)
batteryBarNew :: BarConfig
-> Double
-> IO Widget
batteryBarNew battCfg pollSeconds = do
battCtxt <- batteryContextNew
case battCtxt of
Nothing -> do
let lbl :: Maybe String
lbl = Just "No battery"
labelNew lbl >>= return . toWidget
Just ctxt -> do
b <- hBoxNew False 1
txt <- textBatteryNew "$percentage$%" pollSeconds
r <- newIORef ctxt
bar <- pollingBarNew battCfg pollSeconds (battPct r)
boxPackStart b bar PackNatural 0
boxPackStart b txt PackNatural 0
widgetShowAll b
return (toWidget b)