taffybar-5.2.0: src/System/Taffybar/Widget/DiskUsage.hs
{-# LANGUAGE OverloadedStrings #-}
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- |
-- Module : System.Taffybar.Widget.DiskUsage
-- Copyright : (c) Ivan A. Malison
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Ivan A. Malison
-- Stability : unstable
-- Portability : unportable
--
-- A label widget that displays disk usage information, backed by a shared
-- polling thread from "System.Taffybar.Information.DiskUsage".
--
-- Template variables: @$total$@, @$used$@, @$free$@, @$available$@,
-- @$usedPercent$@, @$freePercent$@, @$path$@.
-- @$free$@ and @$available$@ both report space available to unprivileged users
-- (the @Avail@ value from @df@).
--
-- Size values are auto-formatted with appropriate units (GiB, TiB, etc.).
module System.Taffybar.Widget.DiskUsage
( DiskUsageWidgetConfig (..),
defaultDiskUsageWidgetConfig,
diskUsageIconNew,
diskUsageIconNewWith,
diskUsageLabelNew,
diskUsageLabelNewWith,
diskUsageNew,
diskUsageNewWith,
)
where
import Control.Monad (void)
import Control.Monad.IO.Class
import Data.Default (Default (..))
import qualified Data.Text as T
import qualified GI.Gtk as Gtk
import System.Taffybar.Context (TaffyIO)
import System.Taffybar.Information.DiskUsage
import System.Taffybar.Util (postGUIASync)
import System.Taffybar.Widget.Generic.ChannelWidget
import System.Taffybar.Widget.Util (buildIconLabelBox, widgetSetClassGI)
import Text.Printf (printf)
import Text.StringTemplate
-- | Configuration for disk usage widgets.
data DiskUsageWidgetConfig = DiskUsageWidgetConfig
{ -- | Filesystem path to monitor (default @\/@).
diskUsagePath :: FilePath,
-- | Polling interval in seconds (default 60).
diskUsagePollInterval :: Double,
-- | Label format string (default @\"$free$\"@).
diskUsageFormat :: String,
-- | Optional tooltip format string.
diskUsageTooltipFormat :: Maybe String,
-- | Nerd font icon character (default U+F0A0, ).
diskUsageIcon :: T.Text
}
-- | Default disk usage widget configuration.
defaultDiskUsageWidgetConfig :: DiskUsageWidgetConfig
defaultDiskUsageWidgetConfig =
DiskUsageWidgetConfig
{ diskUsagePath = "/",
diskUsagePollInterval = 60,
diskUsageFormat = "$free$",
diskUsageTooltipFormat =
Just "$path$: $used$ / $total$ ($usedPercent$% used)",
diskUsageIcon = T.pack "\xF0A0" --
}
instance Default DiskUsageWidgetConfig where
def = defaultDiskUsageWidgetConfig
-- | Create a disk usage label with default settings (monitors @/@, 60s poll).
diskUsageLabelNew :: TaffyIO Gtk.Widget
diskUsageLabelNew = diskUsageLabelNewWith defaultDiskUsageWidgetConfig
-- | Create a disk usage label with the given configuration.
diskUsageLabelNewWith :: DiskUsageWidgetConfig -> TaffyIO Gtk.Widget
diskUsageLabelNewWith config = do
let path = diskUsagePath config
interval = diskUsagePollInterval config
chan <- getDiskUsageInfoChan interval path
initialInfo <- getDiskUsageInfoState interval path
liftIO $ do
label <- Gtk.labelNew Nothing
_ <- widgetSetClassGI label "disk-usage-label"
let updateLabel info = postGUIASync $ do
let (labelText, tooltipText) = formatDiskUsage config info
Gtk.labelSetText label labelText
Gtk.widgetSetTooltipText label tooltipText
void $ Gtk.onWidgetRealize label $ updateLabel initialInfo
Gtk.widgetShowAll label
(Gtk.toWidget =<< channelWidgetNew label chan updateLabel)
>>= (`widgetSetClassGI` "disk-usage-label")
-- | Create a disk usage icon widget with default configuration.
diskUsageIconNew :: TaffyIO Gtk.Widget
diskUsageIconNew = diskUsageIconNewWith defaultDiskUsageWidgetConfig
-- | Create a disk usage icon widget with the provided configuration.
diskUsageIconNewWith :: DiskUsageWidgetConfig -> TaffyIO Gtk.Widget
diskUsageIconNewWith config = liftIO $ do
label <- Gtk.labelNew (Just (diskUsageIcon config))
_ <- widgetSetClassGI label "disk-usage-icon"
Gtk.widgetShowAll label
Gtk.toWidget label
-- | Create a combined icon+label disk usage widget with default configuration.
diskUsageNew :: TaffyIO Gtk.Widget
diskUsageNew = diskUsageNewWith defaultDiskUsageWidgetConfig
-- | Create a combined icon+label disk usage widget.
diskUsageNewWith :: DiskUsageWidgetConfig -> TaffyIO Gtk.Widget
diskUsageNewWith config = do
iconWidget <- diskUsageIconNewWith config
labelWidget <- diskUsageLabelNewWith config
liftIO $
buildIconLabelBox iconWidget labelWidget
>>= (`widgetSetClassGI` "disk-usage")
-- --------------------------------------------------------------------------
-- Formatting
formatDiskUsage :: DiskUsageWidgetConfig -> DiskUsageInfo -> (T.Text, Maybe T.Text)
formatDiskUsage config info =
let attrs = diskUsageAttrs (diskUsagePath config) info
labelText = renderTpl (diskUsageFormat config) attrs
tooltipText = renderTpl <$> diskUsageTooltipFormat config <*> pure attrs
in (labelText, tooltipText)
renderTpl :: String -> [(String, String)] -> T.Text
renderTpl template attrs =
T.pack $ render $ setManyAttrib attrs (newSTMP template)
diskUsageAttrs :: FilePath -> DiskUsageInfo -> [(String, String)]
diskUsageAttrs path info =
[ ("total", formatBytes (diskInfoTotal info)),
("used", formatBytes (diskInfoUsed info)),
-- Prefer user-available blocks for the primary "free" template variable.
("free", formatBytes (diskInfoAvailable info)),
("available", formatBytes (diskInfoAvailable info)),
("usedPercent", printf "%.0f" (diskInfoUsedPercent info)),
("freePercent", printf "%.0f" (diskInfoFreePercent info)),
("path", path)
]
-- | Format a byte count with auto-scaled units.
formatBytes :: Integer -> String
formatBytes bytes
| gb >= 1024 = printf "%.1f TiB" (gb / 1024 :: Double)
| gb >= 1 = printf "%.1f GiB" gb
| mb >= 1 = printf "%.0f MiB" mb
| otherwise = printf "%.0f KiB" kb
where
kb = fromIntegral bytes / 1024 :: Double
mb = kb / 1024
gb = mb / 1024