packages feed

xmobar 0.32 → 0.33

raw patch · 31 files changed

+829/−302 lines, 31 filesdep +bsd-sysctldep +cerealdep +netlink

Dependencies added: bsd-sysctl, cereal, netlink

Files

changelog.md view
@@ -1,4 +1,29 @@-## Version 0.32+## Version 0.33 (February, 2020)++_New features_++  - New template parameter `<weather>` for the `Weather` plugin, potentially+    displaying specific weather conditions that are occurring near the+    station (thanks to *slotThe*).+  - New option `--weathers`, for `Weather` to display a default string in+    case the `weather` field is not reported (thanks to *slotThe*).+  - New template parameter `<volumestatus>` for the `Volume` plugin, combining+    the effects of `<volume>` and `<status>`.  This will show the volume+    (possibly prefixed by `onString` or a percentage-based string) if and only+    if the volume is not muted.  Otherwise it will show the+    `offString` (thanks to *slotThe*).+  - `Battery` and `BatteryN` now support FreeBSD (thanks to Dhananjay+    Balan).+  - New option `--useManager` for `Weather` and `UVMeter` to decide whether to+    use one single manager per monitor for managing network connections or+    create a new one every time a connection is made.+  - New more efficient time coalescing strategy for monitor updates,+    available with the threaded runtime: use the `with_threaded` flag+    to enable it (see #410; thanks to Tomáš Janoušek).+  - `Wireless` supports current nl80211 API on Linux now, old Wext ioctls still+    available as compile-time option (thanks to Paul Fertser).++## Version 0.32 (December, 2019)  _New features_ 
readme.md view
@@ -117,12 +117,16 @@   option is needed for the MBox and Mail plugins to work. Requires the   [hinotify] package. -- `with_iwlib` Support for wireless cards. Enables the Wireless-   plugin. No Haskell library is required, but you will need the-   [iwlib] C library and headers in your system (e.g., install-   `libiw-dev` in Debian-based systems or `wireless_tools` on Arch-   Linux).+- `with_nl80211` Support for wireless cards on Linux via nl80211 (all+   upstream drivers). Enables the Wireless plugin. Requires [netlink]+   and [cereal] packages. +- `with_iwlib` Support for wireless cards via Wext ioctls+   (deprecated). Enables the Wireless plugin. No Haskell library is+   required, but you will need the [iwlib] C library and headers in your+   system (e.g., install `libiw-dev` in Debian-based systems or+   `wireless_tools` on Arch Linux). Conflicts with `with_nl80211`.+ - `with_alsa` Support for ALSA sound cards. Enables the Volume    plugin. Requires the [alsa-mixer] package.  To install the latter,    you'll need the [libasound] C library and headers in your system@@ -735,11 +739,20 @@ - Aliases to the Station ID: so `Weather "LIPB" []` can be used in   template as `%LIPB%` - Thresholds refer to temperature in the selected units-- Args: default monitor arguments+- Args: default monitor arguments, plus:+  - `--weathers` _string_ : display a default string when the `weather`+    variable is not reported.+    - short option: `-w`+    - Default: ""+  - `--useManager` _bool_ : Whether to use one single manager per monitor for+    managing network connections or create a new one every time a connection is+    made.+    - Short option: `-m`+    - Default: True - Variables that can be used with the `-t`/`--template` argument: 	    `station`, `stationState`, `year`, `month`, `day`, `hour`, 	    `windCardinal`, `windAzimuth`, `windMph`, `windKnots`, `windMs`, `windKmh`-        `visibility`, `skyCondition`, `tempC`, `tempF`,+        `visibility`, `skyCondition`, `weather`, `tempC`, `tempF`, 	    `dewPointC`, `dewPointF`, `rh`, `pressure` - Default template: `<station>: <tempC>C, rh <rh>% (<hour>)` - Retrieves weather information from http://tgftp.nws.noaa.gov.@@ -811,18 +824,21 @@  ### `Wireless Interface Args RefreshRate` -- If set to "", the interface is looked up in /proc/net/wireless.+- If set to "", first suitable wireless interface is used. - Aliases to the interface name with the suffix "wi": thus, `Wireless   "wlan0" []` can be used as `%wlan0wi%`, and `Wireless "" []` as `%wi%`. - Args: default monitor arguments, plus:   - `--quality-icon-pattern`: dynamic string for connection quality in `qualityipat`. - Variables that can be used with the `-t`/`--template` argument:-            `essid`, `quality`, `qualitybar`, `qualityvbar`, `qualityipat`-- Thresholds refer to link quality in a `[0, 100]` scale-- Default template: `<essid> <quality>`-- Requires the C library [iwlib] (part of the wireless tools suite)-  installed in your system. In addition, to activate this plugin you-  must pass `--flags="with_iwlib"` during compilation+            `ssid`, `signal`, `quality`, `qualitybar`, `qualityvbar`, `qualityipat`+- Thresholds refer to link quality on a `[0, 100]` scale. Note that+  `quality` is calculated from `signal` (in dBm) by a possibly lossy+  conversion. It is also not taking into account many factors such as+  noise level, air busy time, transcievers' capabilities and the+  others which can have drastic impact on the link performance.+- Default template: `<ssid> <quality>`+- To activate this plugin you must pass `--flags="with_nl80211"` or+  `--flags="with_iwlib"` during compilation  ### `Memory Args RefreshRate` @@ -924,7 +940,7 @@     threshold (default: "")   - `--mediums`: string for AC "off" status and power lower than the `-H`     threshold (default: "")-  - `--high`: string for AC "off" status and power higher than the `-H`+  - `--highs`: string for AC "off" status and power higher than the `-H`     threshold (default: "")  @@ -1178,7 +1194,8 @@           Defaults to "".         - Long option: `--lows` - Variables that can be used with the `-t`/`--template` argument:-            `volume`, `volumebar`, `volumevbar`, `volumeipat`, `dB`, `status`+            `volume`, `volumebar`, `volumevbar`, `volumeipat`, `dB`, `status`,+            `volumestatus` - Note that `dB` might only return 0 on your system. This is known   to happen on systems with a pulseaudio backend. - Default template: `Vol: <volume>% <status>`@@ -1409,9 +1426,14 @@  ### `UVMeter` -- Aliases to "uv " + station id. For example: `%uv brisbane%` or `%uv-  alice springs%`-- Args: default monitor arguments.+- Aliases to "uv " + station id. For example: `%uv Brisbane%` or `%uv+  Alice Springs%`+- Args: default monitor arguments, plus:+  - `--useManager` _bool_ : Whether to use one single manager per monitor for+    managing network connections or create a new one every time a connection is+    made.+    - Short option: `-m`+    - Default: True  - *Reminder:* Keep the refresh rate high, to avoid making unnecessary   requests every time the plug-in is run.@@ -1419,7 +1441,7 @@   http://www.arpansa.gov.au/uvindex/realtime/xml/uvvalues.xml - Example: -        Run UVMeter "brisbane" ["-H", "3", "-L", "3", "--low", "green", "--high", "red"] 900+        Run UVMeter "Brisbane" ["-H", "3", "-L", "3", "--low", "green", "--high", "red"] 900  ## Executing External Commands @@ -1667,20 +1689,20 @@ with the help of the greater xmobar and Haskell communities.  In particular, xmobar [incorporates patches] by Mohammed Alshiekh,-Alex Ameen, Axel Angel, Claudio Bley, Dragos Boca, Ben Boeckel, Duncan-Burke, Roman Cheplyaka, Patrick Chilton, Antoine Eiche, Nathaniel-Wesley Filardo, John Goerzen, Reto Hablützel, Juraj Hercek, Tomáš-Janoušek, Ada Joule, Spencer Janssen, Roman Joost, Jochen Keil,-Lennart Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Todd-Lunter, Vanessa McHale, Robert J. Macomber, Dmitry Malikov, David-McLean, Marcin Mikołajczyk, Dino Morelli, Tony Morris, Eric Mrak,-Thiago Negri, Edward O'Callaghan, Svein Ove, Martin Perner, Jens-Petersen, Alexander Polakov, Pavan Rikhi, Petr Rockai, Andrew Emmanuel-Rosa, Sackville-West, Markus Scherer, Daniel Schüssler, Olivier-Schneider, Alexander Shabalin, Valentin Shirokov, Peter Simons,-Alexander Solovyov, Will Song, John Soros, Felix Springer, Travis-Staton, Artem Tarasov, Samuli Thomasson, Edward Tjörnhammar, Sergei-Trofimovich, Thomas Tuegel, John Tyree, Jan Vornberger, Anton+Alex Ameen, Axel Angel, Dhananjay Balan, Claudio Bley, Dragos Boca,+Ben Boeckel, Duncan Burke, Roman Cheplyaka, Patrick Chilton, Antoine+Eiche, Nathaniel Wesley Filardo, John Goerzen, Reto Hablützel, Juraj+Hercek, Tomáš Janoušek, Ada Joule, Spencer Janssen, Roman Joost,+Jochen Keil, Lennart Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry+Kurochkin, Todd Lunter, Vanessa McHale, Robert J. Macomber, Dmitry+Malikov, David McLean, Marcin Mikołajczyk, Dino Morelli, Tony Morris,+Eric Mrak, Thiago Negri, Edward O'Callaghan, Svein Ove, Martin Perner,+Jens Petersen, Alexander Polakov, Pavan Rikhi, Petr Rockai, Andrew+Emmanuel Rosa, Sackville-West, Markus Scherer, Daniel Schüssler,+Olivier Schneider, Alexander Shabalin, Valentin Shirokov, Peter+Simons, Alexander Solovyov, Will Song, John Soros, Felix Springer,+Travis Staton, Artem Tarasov, Samuli Thomasson, Edward Tjörnhammar,+Sergei Trofimovich, Thomas Tuegel, John Tyree, Jan Vornberger, Anton Vorontsov, Daniel Wagner, Zev Weiss, Phil Xiaojun Hu, Edward Z. Yang and Norbert Zeh. 
src/Xmobar/App/EventLoop.hs view
@@ -17,7 +17,12 @@ ------------------------------------------------------------------------------  -module Xmobar.App.EventLoop (startLoop, startCommand) where+module Xmobar.App.EventLoop+    ( startLoop+    , startCommand+    , newRefreshLock+    , refreshLock+    ) where  import Prelude hiding (lookup) import Graphics.X11.Xlib hiding (textExtents, textWidth)@@ -31,7 +36,7 @@ import Control.Concurrent import Control.Concurrent.Async (Async, async) import Control.Concurrent.STM-import Control.Exception (handle, SomeException(..))+import Control.Exception (bracket_, handle, SomeException(..)) import Data.Bits import Data.Map hiding (foldr, map, filter) import Data.Maybe (fromJust, isJust)@@ -47,7 +52,10 @@ import Xmobar.X11.Draw import Xmobar.X11.Bitmap as Bitmap import Xmobar.X11.Types++#ifndef THREADED_RUNTIME import Xmobar.X11.Events(nextEvent')+#endif  #ifdef XFT import Graphics.X11.Xft@@ -60,15 +68,34 @@ runX :: XConf -> X () -> IO () runX xc f = runReaderT f xc +newRefreshLock :: IO (TMVar ())+newRefreshLock = atomically $ newTMVar ()++refreshLock :: TMVar () -> IO a -> IO a+refreshLock var = bracket_ lock unlock+    where+        lock = atomically $ takeTMVar var+        unlock = atomically $ putTMVar var ()++refreshLockT :: TMVar () -> STM a -> STM a+refreshLockT var action = do+    takeTMVar var+    r <- action+    putTMVar var ()+    return r+ -- | Starts the main event loop and threads-startLoop :: XConf -> TMVar SignalType -> [[([Async ()], TVar String)]]-             -> IO ()-startLoop xcfg@(XConf _ _ w _ _ _ _) sig vs = do+startLoop :: XConf+          -> TMVar SignalType+          -> TMVar ()+          -> [[([Async ()], TVar String)]]+          -> IO ()+startLoop xcfg@(XConf _ _ w _ _ _ _) sig pauser vs = do #ifdef XFT     xftInitFtLibrary #endif     tv <- atomically $ newTVar []-    _ <- forkIO (handle (handler "checker") (checker tv [] vs sig))+    _ <- forkIO (handle (handler "checker") (checker tv [] vs sig pauser)) #ifdef THREADED_RUNTIME     _ <- forkOS (handle (handler "eventer") (eventer sig)) #else@@ -108,15 +135,16 @@            -> [String]            -> [[([Async ()], TVar String)]]            -> TMVar SignalType+           -> TMVar ()            -> IO ()-checker tvar ov vs signal = do-      nval <- atomically $ do+checker tvar ov vs signal pauser = do+      nval <- atomically $ refreshLockT pauser $ do               nv <- mapM concatV vs               guard (nv /= ov)               writeTVar tvar nv               return nv       atomically $ putTMVar signal Wakeup-      checker tvar nval vs signal+      checker tvar nval vs signal pauser     where       concatV = fmap concat . mapM (readTVar . snd) 
src/Xmobar/App/Main.hs view
@@ -40,9 +40,10 @@ import Xmobar.X11.Text import Xmobar.X11.Window import Xmobar.App.Opts (recompileFlag, verboseFlag, getOpts, doOpts)-import Xmobar.App.EventLoop (startLoop, startCommand)+import Xmobar.App.EventLoop (startLoop, startCommand, newRefreshLock, refreshLock) import Xmobar.App.Compile (recompile, trace) import Xmobar.App.Config+import Xmobar.App.Timer (withTimer)  xmobar :: Config -> IO () xmobar conf = withDeferSignals $ do@@ -53,14 +54,16 @@   cls   <- mapM (parseTemplate (commands conf) (sepChar conf))                 (splitTemplate (alignSep conf) (template conf))   sig   <- setupSignalHandler-  bracket (mapM (mapM $ startCommand sig) cls)-          cleanupThreads-          $ \vars -> do-    (r,w) <- createWin d fs conf-    let ic = Map.empty-        to = textOffset conf-        ts = textOffsets conf ++ replicate (length fl) (-1)-    startLoop (XConf d r w (fs:fl) (to:ts) ic conf) sig vars+  refLock <- newRefreshLock+  withTimer (refreshLock refLock) $+    bracket (mapM (mapM $ startCommand sig) cls)+            cleanupThreads+            $ \vars -> do+      (r,w) <- createWin d fs conf+      let ic = Map.empty+          to = textOffset conf+          ts = textOffsets conf ++ replicate (length fl) (-1)+      startLoop (XConf d r w (fs:fl) (to:ts) ic conf) sig refLock vars  configFromArgs :: Config -> IO Config configFromArgs cfg = getArgs >>= getOpts >>= doOpts cfg . fst
+ src/Xmobar/App/Timer.hs view
@@ -0,0 +1,221 @@+{-# LANGUAGE LambdaCase #-}+------------------------------------------------------------------------------+-- |+-- Module: Xmobar.App.Timer+-- Copyright: (c) 2019 Tomáš Janoušek+-- License: BSD3-style (see LICENSE)+--+-- Maintainer: Tomáš Janoušek <tomi@nomi.cz>+-- Stability: unstable+--+-- Timer coalescing for recurring actions.+--+------------------------------------------------------------------------------++module Xmobar.App.Timer+    ( doEveryTenthSeconds+    , tenthSeconds+    , withTimer+    ) where++import Control.Concurrent (threadDelay)+import Control.Concurrent.Async (withAsync)+import Control.Concurrent.STM+import Control.Exception+import Control.Monad (forever, forM, guard)+import Data.Foldable (foldrM, for_)+import Data.Int (Int64)+import Data.Map (Map)+import qualified Data.Map as M+import Data.Maybe (isJust, fromJust)+import Data.Time.Clock.POSIX (getPOSIXTime)+import Data.Unique+import System.IO.Unsafe (unsafePerformIO)++type Periods = Map Unique Period++data Tick = Tick (TMVar ()) | UnCoalesce++data Period = Period { rate :: Int64, next :: Int64, tick :: TMVar Tick }++data UnCoalesceException = UnCoalesceException deriving Show+instance Exception UnCoalesceException++{-# NOINLINE periodsVar #-}+periodsVar :: TVar (Maybe Periods)+periodsVar = unsafePerformIO $ newTVarIO Nothing++now :: IO Int64+now = do+    posix <- getPOSIXTime+    return $ floor (10 * posix)++newPeriod :: Int64 -> IO (Unique, Period)+newPeriod r = do+    u <- newUnique+    t <- now+    v <- atomically newEmptyTMVar+    let t' = t - t `mod` r+    return (u, Period { rate = r, next = t', tick = v })++-- | Perform a given action every N tenths of a second.+--+-- The timer is aligned (coalesced) with other timers to minimize the number+-- of wakeups and unnecessary redraws. If the action takes too long (one+-- second or when the next timer is due), coalescing is disabled for it and it+-- falls back to periodic sleep.+doEveryTenthSeconds :: Int -> IO () -> IO ()+doEveryTenthSeconds r action =+    doEveryTenthSecondsCoalesced r action `catch` \UnCoalesceException ->+        doEveryTenthSecondsSleeping r action++-- | Perform a given action every N tenths of a second,+-- coalesce with other timers using a given Timer instance.+doEveryTenthSecondsCoalesced :: Int -> IO () -> IO ()+doEveryTenthSecondsCoalesced r action = do+    (u, p) <- newPeriod (fromIntegral r)+    bracket_ (push u p) (pop u) $ forever $ bracket (wait p) done $ const action+    where+        push u p = atomically $ modifyTVar' periodsVar $ \case+            Just periods -> Just $ M.insert u p periods+            Nothing -> throw UnCoalesceException+        pop u = atomically $ modifyTVar' periodsVar $ \case+            Just periods -> Just $ M.delete u periods+            Nothing -> Nothing++        wait p = atomically (takeTMVar $ tick p) >>= \case+            Tick doneVar -> return doneVar+            UnCoalesce -> throwIO UnCoalesceException+        done doneVar = atomically $ putTMVar doneVar ()++-- | Perform a given action every N tenths of a second,+-- making no attempt to synchronize with other timers.+doEveryTenthSecondsSleeping :: Int -> IO () -> IO ()+doEveryTenthSecondsSleeping r action = go+    where go = action >> tenthSeconds r >> go++-- | Sleep for a given amount of tenths of a second.+--+-- (Work around the Int max bound: since threadDelay takes an Int, it+-- is not possible to set a thread delay grater than about 45 minutes.+-- With a little recursion we solve the problem.)+tenthSeconds :: Int -> IO ()+tenthSeconds s | s >= x = do threadDelay (x * 100000)+                             tenthSeconds (s - x)+               | otherwise = threadDelay (s * 100000)+               where x = (maxBound :: Int) `div` 100000++-- | Start the timer coordination thread and perform a given IO action (this+-- is meant to surround the entire xmobar execution), terminating the timer+-- thread afterwards.+--+-- Additionally, if the timer thread fails, individual+-- 'doEveryTenthSecondsCoalesced' invocations that are waiting to be+-- coordinated by it are notified to fall back to periodic sleeping.+--+-- The timer thread _will_ fail immediately when running in a non-threaded+-- RTS.+withTimer :: (IO () -> IO ()) -> IO a -> IO a+withTimer pauseRefresh action =+    withAsync (timerThread `finally` cleanup) $ const action+    where+        timerThread = do+            atomically $ writeTVar periodsVar $ Just M.empty+            timerLoop pauseRefresh++        cleanup = atomically $ readTVar periodsVar >>= \case+            Just periods -> do+                for_ periods unCoalesceTimer'+                writeTVar periodsVar Nothing+            Nothing -> return ()++timerLoop :: (IO () -> IO ()) -> IO ()+timerLoop pauseRefresh = forever $ do+    tNow <- now+    (toFire, tMaybeNext) <- atomically $ do+        periods <- fromJust <$> readTVar periodsVar+        let toFire = timersToFire tNow periods+        let periods' = advanceTimers tNow periods+        let tMaybeNext = nextFireTime periods'+        writeTVar periodsVar $ Just periods'+        return (toFire, tMaybeNext)+    pauseRefresh $ do+        -- To avoid multiple refreshes, pause refreshing for up to 1 second,+        -- fire timers and wait for them to finish (update their text).+        -- Those that need more time (e.g. weather monitors) will be dropped+        -- from timer coalescing and will fall back to periodic sleep.+        timeoutVar <- registerDelay $ case tMaybeNext of+            Just tNext -> fromIntegral ((tNext - tNow) `max` 10) * 100000+            Nothing -> 1000000+        fired <- fireTimers toFire+        timeouted <- waitForTimers timeoutVar fired+        unCoalesceTimers timeouted+    delayUntilNextFire++advanceTimers :: Int64 -> Periods -> Periods+advanceTimers t = M.map advance+    where+        advance p | next p <= t = p { next = t - t `mod` rate p + rate p }+                  | otherwise = p++timersToFire :: Int64 -> Periods -> [(Unique, Period)]+timersToFire t periods = [ (u, p) | (u, p) <- M.toList periods, next p <= t ]++nextFireTime :: Periods -> Maybe Int64+nextFireTime periods+    | M.null periods = Nothing+    | otherwise = Just $ minimum [ next p | p <- M.elems periods ]++fireTimers :: [(Unique, Period)] -> IO [(Unique, TMVar ())]+fireTimers toFire = atomically $ forM toFire $ \(u, p) -> do+    doneVar <- newEmptyTMVar+    putTMVar (tick p) (Tick doneVar)+    return (u, doneVar)++waitForTimers :: TVar Bool -> [(Unique, TMVar ())] -> IO [Unique]+waitForTimers timeoutVar fired = atomically $ do+    timeoutOver <- readTVar timeoutVar+    dones <- forM fired $ \(u, doneVar) -> do+        done <- isJust <$> tryReadTMVar doneVar+        return (u, done)+    guard $ timeoutOver || all snd dones+    return [u | (u, False) <- dones]++-- | Handle slow timers (drop and signal them to stop coalescing).+unCoalesceTimers :: [Unique] -> IO ()+unCoalesceTimers timers = atomically $ do+    periods <- fromJust <$> readTVar periodsVar+    periods' <- foldrM unCoalesceTimer periods timers+    writeTVar periodsVar $ Just periods'++unCoalesceTimer :: Unique -> Periods -> STM Periods+unCoalesceTimer u periods = do+    unCoalesceTimer' (periods M.! u)+    return $ u `M.delete` periods++unCoalesceTimer' :: Period -> STM ()+unCoalesceTimer' p = do+    _ <- tryTakeTMVar (tick p)+    putTMVar (tick p) UnCoalesce++delayUntilNextFire :: IO ()+delayUntilNextFire = do+    Just periods <- readTVarIO periodsVar+    let tMaybeNext = nextFireTime periods+    tNow <- now+    delayVar <- case tMaybeNext of+        Just tNext -> do+            -- Work around the Int max bound: threadDelay takes an Int, we can+            -- only sleep for so long, which is okay, we'll just check timers+            -- sooner and sleep again.+            let maxDelay = (maxBound :: Int) `div` 100000+                delay = (tNext - tNow) `min` fromIntegral maxDelay+                delayUsec = fromIntegral delay * 100000+            registerDelay delayUsec+        Nothing -> atomically $ newTVar False+    atomically $ do+        delayOver <- readTVar delayVar+        periods' <- fromJust <$> readTVar periodsVar+        let tMaybeNext' = nextFireTime periods'+        -- Return also if a new period is added (it may fire sooner).+        guard $ delayOver || tMaybeNext /= tMaybeNext'
src/Xmobar/Plugins/DateZone.hs view
@@ -72,7 +72,7 @@        else         go (date f locale) -      where go func = func >>= cb >> tenthSeconds r >> go func+      where go func = doEveryTenthSeconds r $ func >>= cb  {-# NOINLINE localeLock #-} -- ensures that only one plugin instance sets the locale
src/Xmobar/Plugins/MBox.hs view
@@ -19,6 +19,7 @@ import Xmobar.Run.Exec #ifdef INOTIFY +import Xmobar.Plugins.Monitors.Common (parseOptsWith) import Xmobar.System.Utils (changeLoop, expandHome)  import Control.Monad (when)@@ -63,12 +64,6 @@   , Option "s" ["suffix"] (ReqArg (\x o -> o { oSuffix = x }) "") ""   ] -parseOptions :: [String] -> IO Options-parseOptions args =-  case getOpt Permute options args of-    (o, _, []) -> return $ foldr id defaults o-    (_, _, errs) -> ioError . userError $ concat errs- #else import System.IO #endif@@ -86,7 +81,7 @@           " but the MBox plugin requires it" #else   start (MBox boxes args _) cb = do-    opts <- parseOptions args+    opts <- parseOptsWith options defaults args     let showAll = oAll opts         prefix = oPrefix opts         suffix = oSuffix opts
src/Xmobar/Plugins/Mail.hs view
@@ -18,6 +18,7 @@ import Xmobar.Run.Exec #ifdef INOTIFY +import Xmobar.Plugins.Monitors.Common (parseOptsWith) import Xmobar.System.Utils (expandHome, changeLoop)  import Control.Monad@@ -64,13 +65,6 @@   , Option "s" ["suffix"] (ReqArg (\x o -> o { oSuffix = x }) "") ""   ] -parseOptions :: [String] -> IO MOptions-parseOptions args =-  case getOpt Permute options args of-    (o, _, []) -> return $ foldr id defaults o-    (_, _, errs) -> ioError . userError $ concat errs-- -- | A list of mail box names and paths to maildirs. data Mail = Mail [(String, FilePath)] String     deriving (Read, Show)@@ -92,7 +86,7 @@ #else     start (MailX ms args _) cb = do         vs <- mapM (const $ newTVarIO S.empty) ms-        opts <- parseOptions args+        opts <- parseOptsWith options defaults args         let prefix = oPrefix opts             suffix = oSuffix opts             dir = oDir opts
src/Xmobar/Plugins/Monitors.hs view
@@ -19,7 +19,7 @@  import Xmobar.Run.Exec -import Xmobar.Plugins.Monitors.Common (runM, runMD)+import Xmobar.Plugins.Monitors.Common (runM) #ifdef WEATHER import Xmobar.Plugins.Monitors.Weather #endif@@ -42,12 +42,12 @@ #ifdef UVMETER import Xmobar.Plugins.Monitors.UVMeter #endif-#ifdef IWLIB+#if defined IWLIB || defined USE_NL80211 import Xmobar.Plugins.Monitors.Wireless #endif #ifdef LIBMPD import Xmobar.Plugins.Monitors.MPD-import Xmobar.Plugins.Monitors.Common (runMBD)+import Xmobar.Plugins.Monitors.Common (runMBD, runMD) #endif #ifdef ALSA import Xmobar.Plugins.Monitors.Volume@@ -85,7 +85,7 @@ #ifdef UVMETER               | UVMeter      Station     Args Rate #endif-#ifdef IWLIB+#if defined IWLIB || defined USE_NL80211               | Wireless Interface  Args Rate #endif #ifdef LIBMPD@@ -142,7 +142,7 @@ #ifdef UVMETER     alias (UVMeter s _ _) = "uv " ++ s #endif-#ifdef IWLIB+#if defined IWLIB || defined USE_NL80211     alias (Wireless i _ _) = i ++ "wi" #endif #ifdef LIBMPD@@ -164,8 +164,8 @@     start (TopProc a r) = startTop a r     start (TopMem a r) = runM a topMemConfig runTopMem r #ifdef WEATHER-    start (Weather s a r) = runMD (a ++ [s]) weatherConfig runWeather r weatherReady-    start (WeatherX s c a r) = runMD (a ++ [s]) weatherConfig (runWeather' c) r weatherReady+    start (Weather  s   a r) = startWeather    s a r+    start (WeatherX s c a r) = startWeather' c s a r #endif     start (Thermal z a r) = runM (a ++ [z]) thermalConfig runThermal r     start (ThermalZone z a r) =@@ -184,9 +184,9 @@     start (Uptime a r) = runM a uptimeConfig runUptime r     start (CatInt _ s a r) = runM a catIntConfig (runCatInt s) r #ifdef UVMETER-    start (UVMeter s a r) = runM (a ++ [s]) uvConfig runUVMeter r+    start (UVMeter s a r) = startUVMeter s a r #endif-#ifdef IWLIB+#if defined IWLIB || defined USE_NL80211     start (Wireless i a r) = runM a wirelessConfig (runWireless i) r #endif #ifdef LIBMPD
src/Xmobar/Plugins/Monitors/Alsa.hs view
@@ -57,17 +57,12 @@   where     modifyVolumeOpts f o = o { aoVolumeOpts = f (aoVolumeOpts o) } -parseOpts :: [String] -> IO AlsaOpts-parseOpts argv =-    case getOpt Permute options argv of-        (o, _, []) -> return $ foldr id defaultOpts o-        (_, _, errs) -> ioError . userError $ concat errs-+-- | Drop generic Monitor args first, then apply 'parseOptsWith' in order to+-- parse everything. parseOptsIncludingMonitorArgs :: [String] -> IO AlsaOpts parseOptsIncludingMonitorArgs args =-    -- Drop generic Monitor args first     case getOpt Permute [] args of-      (_, args', _) -> parseOpts args'+        (_, args', _) -> parseOptsWith options defaultOpts args'  startAlsaPlugin :: String -> String -> [String] -> (String -> IO ()) -> IO () startAlsaPlugin mixerName controlName args cb = do@@ -80,7 +75,7 @@         -- it would have to inline 'runMBD', 'doArgs' and 'parseOpts' to see         -- it, which probably isn't going to happen with the default         -- optimization settings).-        opts2 <- io $ parseOpts args2+        opts2 <- io $ parseOptsWith options defaultOpts args2         Volume.runVolumeWith (aoVolumeOpts opts2) mixerName controlName    withMonitorWaiter mixerName (aoAlsaCtlPath opts) cb $ \wait_ ->
src/Xmobar/Plugins/Monitors/Batt.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE CPP #-}+ ----------------------------------------------------------------------------- -- | -- Module      :  Plugins.Monitors.Batt@@ -17,11 +19,14 @@  import System.Process (system) import Control.Monad (void, unless)-import Control.Exception (SomeException, handle) import Xmobar.Plugins.Monitors.Common+import Control.Exception (SomeException, handle) import System.FilePath ((</>)) import System.IO (IOMode(ReadMode), hGetLine, withFile) import System.Posix.Files (fileExist)+#ifdef FREEBSD+import System.BSD.Sysctl (sysctlReadInt)+#endif import System.Console.GetOpt import Data.List (sort, sortBy, group) import Data.Maybe (fromMaybe)@@ -103,14 +108,8 @@   , Option "" ["highs"] (ReqArg (\x o -> o { highString = x }) "") ""   ] -parseOpts :: [String] -> IO BattOpts-parseOpts argv =-  case getOpt Permute options argv of-    (o, _, []) -> return $ foldr id defaultOpts o-    (_, _, errs) -> ioError . userError $ concat errs- data Status = Charging | Discharging | Full | Idle | Unknown deriving (Read, Eq)-+-- Result perc watts time-seconds Status data Result = Result Float Float Float Status | NA  sysDir :: FilePath@@ -154,6 +153,39 @@  where    c = 100 * min 1 charge +maybeAlert :: BattOpts -> Float -> IO ()+maybeAlert opts left =+  case onLowAction opts of+    Nothing -> return ()+    Just x -> unless (isNaN left || actionThreshold opts < 100 * left)+                $ void $ system x++-- | FreeBSD battery query+#ifdef FREEBSD+battStatusFbsd :: Int -> Status+battStatusFbsd x+  | x == 1 = Discharging+  | x == 2 = Charging+  | otherwise = Unknown++readBatteriesFbsd :: BattOpts -> IO Result+readBatteriesFbsd opts = do+  lf <- sysctlReadInt "hw.acpi.battery.life"+  rt <- sysctlReadInt "hw.acpi.battery.rate"+  tm <- sysctlReadInt "hw.acpi.battery.time"+  st <- sysctlReadInt "hw.acpi.battery.state"+  acline <- sysctlReadInt "hw.acpi.acline"+  let p = fromIntegral lf / 100+      w = fromIntegral rt+      t = fromIntegral tm * 60+      ac = acline == 1+      -- battery full when rate is 0 and on ac.+      sts = if (w == 0 && ac) then Full else (battStatusFbsd $ fromIntegral st)+  unless ac (maybeAlert opts p)+  return (Result p w t sts)++#else+-- | query linux battery safeFileExist :: String -> String -> IO Bool safeFileExist d f = handle noErrors $ fileExist (d </> f)   where noErrors = const (return False) :: SomeException -> IO Bool@@ -195,7 +227,7 @@            a' = max a b -- sometimes the reported max charge is lower than        return $ Battery (3600 * a' / sc') -- wattseconds                         (3600 * b / sc') -- wattseconds-                        (d / sc') -- watts+                        (abs d / sc') -- watts                         s -- string: Discharging/Charging/Full     where grab f = handle onError $ withFile f ReadMode (fmap read . hGetLine)           onError = const (return (-1)) :: SomeException -> IO Float@@ -210,15 +242,8 @@ mostCommonDef :: Eq a => a -> [a] -> a mostCommonDef x xs = head $ last $ [x] : sortOn length (group xs) -maybeAlert :: BattOpts -> Float -> IO ()-maybeAlert opts left =-  case onLowAction opts of-    Nothing -> return ()-    Just x -> unless (isNaN left || actionThreshold opts < 100 * left)-                $ void $ system x--readBatteries :: BattOpts -> [Files] -> IO Result-readBatteries opts bfs =+readBatteriesLinux :: BattOpts -> [Files] -> IO Result+readBatteriesLinux opts bfs =     do let bfs' = filter (/= NoFiles) bfs        bats <- mapM (readBattery (scale opts)) (take 3 bfs')        ac <- haveAc (onlineFile opts)@@ -239,25 +264,34 @@                  | otherwise = Discharging        unless ac (maybeAlert opts left)        return $ if isNaN left then NA else Result left watts time racst+#endif  runBatt :: [String] -> Monitor String runBatt = runBatt' ["BAT", "BAT0", "BAT1", "BAT2"]  runBatt' :: [String] -> [String] -> Monitor String runBatt' bfs args = do-  opts <- io $ parseOpts args-  let sp = incPerc opts-  c <- io $ readBatteries opts =<< mapM batteryFiles bfs+  opts <- io $ parseOptsWith options defaultOpts args+#ifdef FREEBSD+  c <- io $ readBatteriesFbsd opts+#else+  c <- io $ readBatteriesLinux opts =<< mapM batteryFiles bfs+#endif+  formatResult c opts++formatResult :: Result -> BattOpts -> Monitor String+formatResult res bopt = do+  let sp = incPerc bopt   suffix <- getConfigValue useSuffix   d <- getConfigValue decDigits   nas <- getConfigValue naString-  case c of+  case res of     Result x w t s ->       do l <- fmtPercent x sp-         ws <- fmtWatts w opts suffix d-         si <- getIconPattern opts s x+         ws <- fmtWatts w bopt suffix d+         si <- getIconPattern bopt s x          st <- showWithColors'-                 (fmtStatus opts s nas (getBattStatus x opts))+                 (fmtStatus bopt s nas (getBattStatus x bopt))                  (100 * x)          parseTemplate (l ++ [st, fmtTime $ floor t, ws, si])     NA -> getConfigValue naString
src/Xmobar/Plugins/Monitors/Bright.hs view
@@ -44,13 +44,6 @@              o { curBrightIconPattern = Just $ parseIconPattern x }) "") ""           ] --- from Batt.hs-parseOpts :: [String] -> IO BrightOpts-parseOpts argv =-  case getOpt Permute options argv of-    (o, _, []) -> return $ foldr id defaultOpts o-    (_, _, errs) -> ioError . userError $ concat errs- sysDir :: FilePath sysDir = "/sys/class/backlight/" @@ -75,7 +68,7 @@  runBright :: [String] ->  Monitor String runBright args = do-  opts <- io $ parseOpts args+  opts <- io $ parseOptsWith options defaultOpts args   f <- io $ brightFiles opts   c <- io $ readBright f   case f of
src/Xmobar/Plugins/Monitors/Common/Parsers.hs view
@@ -24,12 +24,14 @@                                               , skipTillString                                               , parseTemplate                                               , parseTemplate'+                                              , parseOptsWith                                               ) where  import Xmobar.Plugins.Monitors.Common.Types  import Control.Applicative ((<$>)) import qualified Data.Map as Map+import System.Console.GetOpt (ArgOrder(Permute), OptDescr, getOpt) import Text.ParserCombinators.Parsec  runP :: Parser [a] -> String -> IO [a]@@ -150,3 +152,14 @@          Nothing -> return $ "<" ++ ts ++ ">"          Just  r -> let f "" = r; f n = n; in f <$> parseTemplate' r m        return $ s ++ str ++ ss ++ next++-- | Try to parse arguments from the config file and apply them to Options.+parseOptsWith+    :: [OptDescr (opts -> opts)]  -- ^ Options that are specifiable+    -> opts                       -- ^ Default options to use as a fallback+    -> [String]                   -- ^ Actual arguments given+    -> IO opts+parseOptsWith options defaultOpts argv =+    case getOpt Permute options argv of+        (o, _, []  ) -> pure $ foldr id defaultOpts o+        (_, _, errs) -> ioError . userError $ concat errs
src/Xmobar/Plugins/Monitors/Common/Run.hs view
@@ -19,6 +19,9 @@                                           , runMD                                           , runMB                                           , runMBD+                                          , runML+                                          , runMLD+                                          , getArgvs                                           ) where  import Control.Exception (SomeException,handle)@@ -27,7 +30,7 @@ import System.Console.GetOpt  import Xmobar.Plugins.Monitors.Common.Types-import Xmobar.Run.Exec (tenthSeconds)+import Xmobar.Run.Exec (doEveryTenthSeconds)  options :: [OptDescr Opts] options =@@ -55,6 +58,13 @@     , Option "E" ["maxtwidthellipsis"] (ReqArg MaxTotalWidthEllipsis "Maximum total width ellipsis") "Ellipsis to be added to the total text when it has reached its max width."     ] +-- | Get all argument values out of a list of arguments.+getArgvs :: [String] -> [String]+getArgvs args =+    case getOpt Permute options args of+        (_, n, []  ) -> n+        (_, _, errs) -> errs+ doArgs :: [String]        -> ([String] -> Monitor String)        -> ([String] -> Monitor Bool)@@ -100,11 +110,11 @@  runM :: [String] -> IO MConfig -> ([String] -> Monitor String) -> Int         -> (String -> IO ()) -> IO ()-runM args conf action r = runMB args conf action (tenthSeconds r)+runM args conf action r = runML args conf action (doEveryTenthSeconds r)  runMD :: [String] -> IO MConfig -> ([String] -> Monitor String) -> Int         -> ([String] -> Monitor Bool) -> (String -> IO ()) -> IO ()-runMD args conf action r = runMBD args conf action (tenthSeconds r)+runMD args conf action r = runMLD args conf action (doEveryTenthSeconds r)  runMB :: [String] -> IO MConfig -> ([String] -> Monitor String) -> IO ()         -> (String -> IO ()) -> IO ()@@ -115,6 +125,17 @@ runMBD args conf action wait detect cb = handle (cb . showException) loop   where ac = doArgs args action detect         loop = conf >>= runReaderT ac >>= cb >> wait >> loop++runML :: [String] -> IO MConfig -> ([String] -> Monitor String)+      -> (IO () -> IO ()) -> (String -> IO ()) -> IO ()+runML args conf action looper = runMLD args conf action looper (\_ -> return True)++runMLD :: [String] -> IO MConfig -> ([String] -> Monitor String)+       -> (IO () -> IO ()) -> ([String] -> Monitor Bool) -> (String -> IO ())+       -> IO ()+runMLD args conf action looper detect cb = handle (cb . showException) loop+  where ac = doArgs args action detect+        loop = looper $ conf >>= runReaderT ac >>= cb  showException :: SomeException -> String showException = ("error: "++) . show . flip asTypeOf undefined
src/Xmobar/Plugins/Monitors/Common/Types.hs view
@@ -25,8 +25,9 @@                                             , io                                             ) where -import Data.IORef-import Control.Monad.Reader+import Control.Monad.Reader (ReaderT, ask, liftIO)+import Data.IORef (IORef, modifyIORef, newIORef, readIORef)+  type Monitor a = ReaderT MConfig IO a 
src/Xmobar/Plugins/Monitors/CoreTemp.hs view
@@ -25,8 +25,7 @@ coreTempConfig :: IO MConfig coreTempConfig = mkMConfig        "Temp: <core0>C" -- template-       (map ((++) "core" . show) [0 :: Int ..]) -- available-                                                -- replacements+       (map ((++) "core" . show) [0 :: Int ..]) -- available replacements  -- | -- Function retrieves monitor string holding the core temperature
src/Xmobar/Plugins/Monitors/Cpu.hs view
@@ -35,12 +35,6 @@      o { loadIconPattern = Just $ parseIconPattern x }) "") ""   ] -parseOpts :: [String] -> IO CpuOpts-parseOpts argv =-  case getOpt Permute options argv of-    (o, _, []) -> return $ foldr id defaultOpts o-    (_, _, errs) -> ioError . userError $ concat errs- cpuConfig :: IO MConfig cpuConfig = mkMConfig        "Cpu: <total>%"@@ -77,7 +71,7 @@ runCpu :: CpuDataRef -> [String] -> Monitor String runCpu cref argv =     do c <- io (parseCpu cref)-       opts <- io $ parseOpts argv+       opts <- io $ parseOptsWith options defaultOpts argv        l <- formatCpu opts c        parseTemplate l 
src/Xmobar/Plugins/Monitors/Disk.hs view
@@ -34,27 +34,25 @@   , contiguous :: Bool   } -parseDiskIOOpts :: [String] -> IO DiskIOOpts-parseDiskIOOpts argv =-  case getOpt Permute options argv of-    (o, _, []) -> return $ foldr id defaultOpts o-    (_, _, errs) -> ioError . userError $ concat errs- where defaultOpts = DiskIOOpts-          { totalIconPattern = Nothing-          , writeIconPattern = Nothing-          , readIconPattern = Nothing-          , contiguous = False-          }-       options =-          [ Option "" ["total-icon-pattern"] (ReqArg (\x o ->-             o { totalIconPattern = Just $ parseIconPattern x}) "") ""-          , Option "" ["write-icon-pattern"] (ReqArg (\x o ->-             o { writeIconPattern = Just $ parseIconPattern x}) "") ""-          , Option "" ["read-icon-pattern"] (ReqArg (\x o ->-             o { readIconPattern = Just $ parseIconPattern x}) "") ""-          , Option "c" ["contiguous"] (NoArg (\o -> o {contiguous = True})) ""-          ]+dioDefaultOpts :: DiskIOOpts+dioDefaultOpts = DiskIOOpts+   { totalIconPattern = Nothing+   , writeIconPattern = Nothing+   , readIconPattern = Nothing+   , contiguous = False+   } +dioOptions :: [OptDescr (DiskIOOpts -> DiskIOOpts)]+dioOptions =+   [ Option "" ["total-icon-pattern"] (ReqArg (\x o ->+      o { totalIconPattern = Just $ parseIconPattern x}) "") ""+   , Option "" ["write-icon-pattern"] (ReqArg (\x o ->+      o { writeIconPattern = Just $ parseIconPattern x}) "") ""+   , Option "" ["read-icon-pattern"] (ReqArg (\x o ->+      o { readIconPattern = Just $ parseIconPattern x}) "") ""+   , Option "c" ["contiguous"] (NoArg (\o -> o {contiguous = True})) ""+   ]+ diskIOConfig :: IO MConfig diskIOConfig = mkMConfig "" ["total", "read", "write"                             ,"totalb", "readb", "writeb"@@ -72,24 +70,22 @@   , contiguousU :: Bool   } -parseDiskUOpts :: [String] -> IO DiskUOpts-parseDiskUOpts argv =-  case getOpt Permute options argv of-    (o, _, []) -> return $ foldr id defaultOpts o-    (_, _, errs) -> ioError . userError $ concat errs- where defaultOpts = DiskUOpts-          { freeIconPattern = Nothing-          , usedIconPattern = Nothing-          , contiguousU = False-          }-       options =-          [ Option "" ["free-icon-pattern"] (ReqArg (\x o ->-             o { freeIconPattern = Just $ parseIconPattern x}) "") ""-          , Option "" ["used-icon-pattern"] (ReqArg (\x o ->-             o { usedIconPattern = Just $ parseIconPattern x}) "") ""-          , Option "c" ["contiguous"] (NoArg (\o -> o {contiguousU = True})) ""-          ]+duDefaultOpts :: DiskUOpts+duDefaultOpts = DiskUOpts+   { freeIconPattern = Nothing+   , usedIconPattern = Nothing+   , contiguousU = False+   } +duOptions :: [OptDescr (DiskUOpts -> DiskUOpts)]+duOptions =+   [ Option "" ["free-icon-pattern"] (ReqArg (\x o ->+      o { freeIconPattern = Just $ parseIconPattern x}) "") ""+   , Option "" ["used-icon-pattern"] (ReqArg (\x o ->+      o { usedIconPattern = Just $ parseIconPattern x}) "") ""+   , Option "c" ["contiguous"] (NoArg (\o -> o {contiguousU = True})) ""+   ]+ diskUConfig :: IO MConfig diskUConfig = mkMConfig ""               [ "size", "free", "used", "freep", "usedp"@@ -208,7 +204,7 @@  runDiskIO :: DevDataRef -> [(String, String)] -> [String] -> Monitor String runDiskIO dref disks argv = do-  opts <- io $ parseDiskIOOpts argv+  opts <- io $ parseOptsWith dioOptions dioDefaultOpts argv   dev <- io $ mountedOrDiskDevices (map fst disks)   dat <- io $ mountedData dref (map fst dev)   strs <- mapM (runDiskIO' opts) $ devTemplates disks dev dat@@ -254,6 +250,6 @@ runDiskU :: [(String, String)] -> [String] -> Monitor String runDiskU disks argv = do   devs <- io $ mountedDevices (map fst disks)-  opts <- io $ parseDiskUOpts argv+  opts <- io $ parseOptsWith duOptions duDefaultOpts argv   strs <- mapM (\(d, p) -> runDiskU' opts (findTempl d p disks) p) devs   return $ (if contiguousU opts then concat else unwords) strs
src/Xmobar/Plugins/Monitors/MPD.hs view
@@ -64,7 +64,7 @@  runMPD :: [String] -> Monitor String runMPD args = do-  opts <- io $ mopts args+  opts <- io $ parseOptsWith options defaultOpts args   status <- io $ withMPD opts M.status   song <- io $ withMPD opts M.currentSong   s <- parseMPD status song opts@@ -79,7 +79,7 @@  mpdReady :: [String] -> Monitor Bool mpdReady args = do-  opts <- io $ mopts args+  opts <- io $ parseOptsWith options defaultOpts args   response <- io $ withMPD opts M.ping   case response of     Right _         -> return True@@ -88,12 +88,6 @@     Left M.NoMPD    -> return False     Left (M.ConnectionError _) -> return False     Left _          -> return True--mopts :: [String] -> IO MOpts-mopts argv =-  case getOpt Permute options argv of-    (o, _, []) -> return $ foldr id defaultOpts o-    (_, _, errs) -> ioError . userError $ concat errs  parseMPD :: M.Response M.Status -> M.Response (Maybe M.Song) -> MOpts             -> Monitor [String]
src/Xmobar/Plugins/Monitors/Mem.hs view
@@ -41,12 +41,6 @@      o { availableIconPattern = Just $ parseIconPattern x }) "") ""   ] -parseOpts :: [String] -> IO MemOpts-parseOpts argv =-  case getOpt Permute options argv of-    (o, _, []) -> return $ foldr id defaultOpts o-    (_, _, errs) -> ioError . userError $ concat errs- memConfig :: IO MConfig memConfig = mkMConfig        "Mem: <usedratio>% (<cache>M)" -- template@@ -91,6 +85,6 @@ runMem :: [String] -> Monitor String runMem argv =     do m <- io parseMEM-       opts <- io $ parseOpts argv+       opts <- io $ parseOptsWith options defaultOpts argv        l <- formatMem opts m        parseTemplate l
src/Xmobar/Plugins/Monitors/MultiCoreTemp.hs view
@@ -60,12 +60,6 @@               ""           ] --- | Parse Arguments and apply them to Options.-parseOpts :: [String] -> IO CTOpts-parseOpts argv = case getOpt Permute options argv of-                   (opts , _ , []  ) -> return $ foldr id defaultOpts opts-                   (_    , _ , errs) -> ioError . userError $ concat errs- -- | Generate Config with a default template and options. cTConfig :: IO MConfig cTConfig = mkMConfig cTTemplate cTOptions@@ -157,7 +151,7 @@  runCT :: [String] -> Monitor String runCT argv = do cTs <- io parseCT-                opts <- io $ parseOpts argv+                opts <- io $ parseOptsWith options defaultOpts argv                 l <- formatCT opts cTs                 parseTemplate l 
src/Xmobar/Plugins/Monitors/MultiCpu.hs view
@@ -47,12 +47,6 @@   , Option "" ["contiguous-icons"] (NoArg (\o -> o {contiguous = True})) ""   ] -parseOpts :: [String] -> IO MultiCpuOpts-parseOpts argv =-  case getOpt Permute options argv of-    (o, _, []) -> return $ foldr id defaultOpts o-    (_, _, errs) -> ioError . userError $ concat errs- variables :: [String] variables = ["bar", "vbar","ipat","total","user","nice","system","idle"] vNum :: Int@@ -122,7 +116,7 @@ runMultiCpu :: CpuDataRef -> [String] -> Monitor String runMultiCpu cref argv =   do c <- io $ parseCpuData cref-     opts <- io $ parseOpts argv+     opts <- io $ parseOptsWith options defaultOpts argv      l <- formatMultiCpus opts c      a <- formatAutoCpus opts l      parseTemplate $ a ++ l
src/Xmobar/Plugins/Monitors/Net.hs view
@@ -68,12 +68,6 @@      o { onlyDevList = Just $ parseDevList x }) "") ""   ] -parseOpts :: [String] -> IO NetOpts-parseOpts argv =-  case getOpt Permute options argv of-    (o, _, []) -> return $ foldr id defaultOpts o-    (_, _, errs) -> ioError . userError $ concat errs- data UnitPerSec = Bs | KBs | MBs | GBs deriving (Eq,Enum,Ord) data NetValue = NetValue Float UnitPerSec deriving (Eq,Show) @@ -188,7 +182,7 @@ runNet :: NetDevRef -> String -> [String] -> Monitor String runNet nref i argv = do   dev <- io $ parseNet nref i-  opts <- io $ parseOpts argv+  opts <- io $ parseOptsWith options defaultOpts argv   printNet opts dev  parseNets :: [(NetDevRef, String)] -> IO [NetDevRate]@@ -196,7 +190,7 @@  runNets :: [(NetDevRef, String)] -> [String] -> Monitor String runNets refs argv = do-  opts <- io $ parseOpts argv+  opts <- io $ parseOptsWith options defaultOpts argv   dev <- io $ parseActive $ filterRefs opts refs   printNet opts dev     where parseActive refs' = fmap selectActive (parseNets refs')
src/Xmobar/Plugins/Monitors/UVMeter.hs view
@@ -19,15 +19,40 @@  import qualified Control.Exception as CE import Network.HTTP.Conduit-       (parseRequest, newManager, tlsManagerSettings, httpLbs,-        responseBody)+    ( Manager+    , httpLbs+    , managerConnCount+    , newManager+    , parseRequest+    , responseBody+    , tlsManagerSettings+    ) import Data.ByteString.Lazy.Char8 as B+import Data.Maybe (fromMaybe)+import System.Console.GetOpt (ArgDescr(ReqArg), OptDescr(Option)) import Text.Read (readMaybe) import Text.Parsec import Text.Parsec.String import Control.Monad (void)  +-- | Options the user may specify.+newtype UVMeterOpts = UVMeterOpts+  { useManager :: Bool+  }++-- | Default values for options.+defaultOpts :: UVMeterOpts+defaultOpts = UVMeterOpts+  { useManager = True+  }++-- | Apply options.+options :: [OptDescr (UVMeterOpts -> UVMeterOpts)]+options =+  [ Option "m" ["useManager"] (ReqArg (\m o -> o { useManager = read m }) "") ""+  ]+ uvConfig :: IO MConfig uvConfig = mkMConfig        "<station>" -- template@@ -40,16 +65,19 @@ uvURL :: String uvURL = "https://uvdata.arpansa.gov.au/xml/uvvalues.xml" -getData :: IO String-getData =-  CE.catch (do request <- parseRequest uvURL-               manager <- newManager tlsManagerSettings-               res <- httpLbs request manager-               return $ B.unpack $ responseBody res)-           errHandler-  where errHandler-          :: CE.SomeException -> IO String-        errHandler _ = return "<Could not retrieve data>"+-- | Get the UV data from the given url.+getData :: Maybe Manager -> IO String+getData uvMan = CE.catch+    (do man <- flip fromMaybe uvMan <$> mkManager+        -- Create a new manager if none was present or the user does not want to+        -- use one, otherwise use the provided manager.+        request <- parseRequest uvURL+        res <- httpLbs request man+        return $ B.unpack $ responseBody res)+    errHandler+  where+    errHandler :: CE.SomeException -> IO String+    errHandler _ = return "<Could not retrieve data>"  textToXMLDocument :: String -> Either ParseError [XML] textToXMLDocument = parse document ""@@ -69,11 +97,23 @@ getUVRating locID (_:xs) = getUVRating locID xs getUVRating _ [] = Nothing +-- | Start the uvmeter monitor, create a new 'Maybe Manager', should the user have+-- chosen to use one.+startUVMeter+    :: String    -- ^ Station+    -> [String]  -- ^ User supplied arguments+    -> Int       -- ^ Update rate+    -> (String -> IO ())+    -> IO ()+startUVMeter station args rate cb = do+    opts  <- parseOptsWith options defaultOpts (getArgvs args)+    uvMan <- tryMakeManager opts+    runM (station : args) uvConfig (runUVMeter uvMan) rate cb -runUVMeter :: [String] -> Monitor String-runUVMeter [] = return "N.A."-runUVMeter (s:_) = do-    resp <- io getData+runUVMeter :: Maybe Manager -> [String] -> Monitor String+runUVMeter _ [] = return "N.A."+runUVMeter uvMan (s:_) = do+    resp <- io $ getData uvMan     case textToXMLDocument resp of         Right doc -> formatUVRating (getUVRating s doc)         Left _ -> getConfigValue naString@@ -155,3 +195,15 @@     char '"'     spaces     return (Attribute (name, value))++-- | Possibly create a new 'Manager', based upon the users preference.  If one+-- is created, this 'Manager' will be used throughout the monitor.+tryMakeManager :: UVMeterOpts -> IO (Maybe Manager)+tryMakeManager opts =+    if useManager opts+        then Just <$> mkManager+        else pure Nothing++-- | Create a new 'Manager' for managing network connections.+mkManager :: IO Manager+mkManager = newManager $ tlsManagerSettings {managerConnCount = 1}
src/Xmobar/Plugins/Monitors/Volume.hs view
@@ -23,16 +23,26 @@  import Control.Applicative ( (<$>), liftA3 ) import Control.Monad ( liftM2, liftM3, mplus )+import Data.Maybe (fromMaybe) import Data.Traversable (sequenceA) import Xmobar.Plugins.Monitors.Common import Sound.ALSA.Mixer import qualified Sound.ALSA.Exception as AE import System.Console.GetOpt -volumeConfig :: IO MConfig-volumeConfig = mkMConfig "Vol: <volume>% <status>"-                         ["volume", "volumebar", "volumevbar", "dB","status", "volumeipat"] +volumeConfig :: IO MConfig+volumeConfig =+    mkMConfig+        "Vol: <volume>% <status>"+        [ "volume"+        , "volumebar"+        , "volumevbar"+        , "dB"+        , "status"+        , "volumeipat"+        , "volumestatus"+        ]  data VolumeOpts = VolumeOpts     { onString :: String@@ -101,12 +111,6 @@     , Option "h" ["highs"] (ReqArg (\x o -> o { highString = x }) "") ""     ] -parseOpts :: [String] -> IO VolumeOpts-parseOpts argv =-    case getOpt Permute options argv of-        (o, _, []) -> return $ foldr id defaultOpts o-        (_, _, errs) -> ioError . userError $ concat errs- percent :: Integer -> Integer -> Integer -> Float percent v' lo' hi' = (v - lo) / (hi - lo)   where v = fromIntegral v'@@ -141,7 +145,7 @@     ++ maybe "" (const "</fc>") (cHelp opts)  formatSwitch :: VolumeOpts -> Bool -> VolumeStatus -> Monitor String-formatSwitch opts True vs = switchHelper opts onColor onString vs+formatSwitch opts True  vs = switchHelper opts onColor  onString  vs formatSwitch opts False _  = switchHelper opts offColor offString VolOff  -- | Convert the current volume status into user defined strings@@ -173,7 +177,7 @@  runVolume :: String -> String -> [String] -> Monitor String runVolume mixerName controlName argv = do-    opts <- io $ parseOpts argv+    opts <- io $ parseOptsWith options defaultOpts argv     runVolumeWith opts mixerName controlName  runVolumeWith :: VolumeOpts -> String -> String -> Monitor String@@ -189,8 +193,14 @@                          (liftA3 percent val lo hi) -- current volume in %     s <- getFormatSwitch opts sw volStat     ipat <- liftMonitor $ liftM3 (formatVolDStr $ volumeIconPattern opts) lo hi val-    parseTemplate [p, b, v, d, s, ipat] +    -- Volume and status in one.+    let vs = if isVolOff sw+            then offString opts -- User defined off string+            else s ++ p         -- Status string, current volume in %++    parseTemplate [p, b, v, d, s, ipat, vs]+   where      readMixer =@@ -244,5 +254,9 @@     getFormatSwitch _ Nothing _ = unavailable     getFormatSwitch _ _ Nothing = unavailable     getFormatSwitch opts' (Just sw) (Just vs) = formatSwitch opts' sw vs++    -- | Determine whether the volume is off based on the value of 'sw' from+    -- 'runVolumeWith'.+    isVolOff = not . fromMaybe False      unavailable = getConfigValue naString
src/Xmobar/Plugins/Monitors/Weather.hs view
@@ -19,14 +19,37 @@  import qualified Control.Exception as CE +import qualified Data.ByteString.Lazy.Char8 as B+import Data.Char (toLower)+import Data.Maybe (fromMaybe) import Network.HTTP.Conduit import Network.HTTP.Types.Status import Network.HTTP.Types.Method-import qualified Data.ByteString.Lazy.Char8 as B-import Data.Char (toLower)  import Text.ParserCombinators.Parsec+import System.Console.GetOpt (ArgDescr(ReqArg), OptDescr(Option)) ++-- | Options the user may specify.+data WeatherOpts = WeatherOpts+  { weatherString :: String+  , useManager    :: Bool+  }++-- | Default values for options.+defaultOpts :: WeatherOpts+defaultOpts = WeatherOpts+  { weatherString = ""+  , useManager    = True+  }++-- | Apply options.+options :: [OptDescr (WeatherOpts -> WeatherOpts)]+options =+  [ Option "w" ["weathers"  ] (ReqArg (\s o -> o { weatherString = s   }) "") ""+  , Option "m" ["useManager"] (ReqArg (\b o -> o { useManager = read b }) "") ""+  ]+ weatherConfig :: IO MConfig weatherConfig = mkMConfig        "<station>: <tempC>C, rh <rh>% (<hour>)" -- template@@ -45,6 +68,7 @@        , "visibility"        , "skyCondition"        , "skyConditionS"+       , "weather"        , "tempC"        , "tempF"        , "dewPointC"@@ -73,6 +97,7 @@        , windInfo     :: WindInfo        , visibility   :: String        , skyCondition :: String+       , weather      :: String        , tempC        :: Int        , tempF        :: Int        , dewPointC    :: Int@@ -169,6 +194,7 @@        w <- pWind        v <- getAfterString "Visibility: "        sk <- getAfterString "Sky conditions: "+       we <- getAfterString "Weather: "        skipTillString "Temperature: "        (tC,tF) <- pTemp        skipTillString "Dew Point: "@@ -178,7 +204,7 @@        skipTillString "Pressure (altimeter): "        p <- pPressure        manyTill skipRestOfLine eof-       return [WI st ss y m d h w v sk tC tF dC dF rh p]+       return [WI st ss y m d h w v sk we tC tF dC dF rh p]  defUrl :: String defUrl = "https://tgftp.nws.noaa.gov/data/observations/metar/decoded/"@@ -186,50 +212,111 @@ stationUrl :: String -> String stationUrl station = defUrl ++ station ++ ".TXT" -getData :: String -> IO String-getData station = CE.catch (do-    manager <- newManager tlsManagerSettings-    request <- parseUrlThrow $ stationUrl station-    res <- httpLbs request manager-    return $  B.unpack $ responseBody res-    ) errHandler-    where errHandler :: CE.SomeException -> IO String-          errHandler _ = return "<Could not retrieve data>"+-- | Get the decoded weather data from the given station.+getData :: Maybe Manager -> String -> IO String+getData weMan station = CE.catch+    (do man <- flip fromMaybe weMan <$> mkManager+        -- Create a new manager if none was present or the user does not want to+        -- use one.+        request <- parseUrlThrow $ stationUrl station+        res <- httpLbs request man+        return $ B.unpack $ responseBody res)+    errHandler+  where+    errHandler :: CE.SomeException -> IO String+    errHandler _ = return "<Could not retrieve data>"  formatSk :: Eq p => [(p, p)] -> p -> p formatSk ((a,b):sks) sk = if a == sk then b else formatSk sks sk formatSk [] sk = sk -formatWeather :: [(String,String)] -> [WeatherInfo] -> Monitor String-formatWeather sks [WI st ss y m d h (WindInfo wc wa wm wk wkh wms) v sk tC tF dC dF r p] =+formatWeather+    :: WeatherOpts        -- ^ Formatting options from the cfg file+    -> [(String,String)]  -- ^ 'SkyConditionS' for 'WeatherX'+    -> [WeatherInfo]      -- ^ The actual weather info+    -> Monitor String+formatWeather opts sks [WI st ss y m d h (WindInfo wc wa wm wk wkh wms) v sk we tC tF dC dF r p] =     do cel <- showWithColors show tC        far <- showWithColors show tF        let sk' = formatSk sks (map toLower sk)+           we' = showWeather (weatherString opts) we        parseTemplate [st, ss, y, m, d, h, wc, wa, wm, wk, wkh-                     , wms, v, sk, sk', cel, far+                     , wms, v, sk, sk', we', cel, far                      , show dC, show dF, show r , show p ]-formatWeather _ _ = getConfigValue naString+formatWeather _ _ _ = getConfigValue naString -runWeather :: [String] -> Monitor String-runWeather = runWeather' []+-- | Show the 'weather' field with a default string in case it was empty.+showWeather :: String -> String -> String+showWeather "" d = d+showWeather s  _ = s -runWeather' :: [(String, String)] -> [String] -> Monitor String-runWeather' sks args =-    do d <- io $ getData $ head args-       i <- io $ runP parseData d-       formatWeather sks i+-- | Start a weather monitor, create a new 'Maybe Manager', should the user have+-- chosen to use one.+startWeather'+    :: [(String, String)]  -- ^ 'SkyConditionS' replacement strings+    -> String              -- ^ Weather station+    -> [String]            -- ^ User supplied arguments+    -> Int                 -- ^ Update rate+    -> (String -> IO ())+    -> IO ()+startWeather' sks station args rate cb = do+    opts  <- parseOptsWith options defaultOpts (getArgvs args)+    weRef <- tryMakeManager opts+    runMD+        (station : args)+        weatherConfig+        (runWeather sks weRef opts)+        rate+        weatherReady+        cb +-- | Same as 'startWeather'', only for 'Weather' instead of 'WeatherX', meaning+-- no 'SkyConditionS'.+startWeather :: String -> [String] -> Int -> (String -> IO ()) -> IO ()+startWeather = startWeather' []++-- | Run a weather monitor.+runWeather+    :: [(String, String)]  -- ^ 'SkyConditionS' replacement strings+    -> Maybe Manager       -- ^ Whether to use a 'Manager'+    -> WeatherOpts         -- ^ Weather specific options+    -> [String]            -- ^ User supplied arguments+    -> Monitor String+runWeather sks weMan opts args = do+    d <- io $ getData weMan (head args)+    i <- io $ runP parseData d+    formatWeather opts sks i+ weatherReady :: [String] -> Monitor Bool-weatherReady str = do+weatherReady str = io $ do     initRequest <- parseUrlThrow $ stationUrl $ head str-    let request = initRequest{method = methodHead}-    io $ CE.catch ( do-        manager <- newManager tlsManagerSettings-        res     <- httpLbs request manager-        return $ checkResult $responseStatus res ) errHandler-    where errHandler :: CE.SomeException -> IO Bool-          errHandler _ = return False-          checkResult status-            | statusIsServerError status = False-            | statusIsClientError status = False-            | otherwise = True+    let request = initRequest { method = methodHead }++    CE.catch+        (do man <- mkManager+            res  <- httpLbs request man+            return $ checkResult $ responseStatus res)+        errHandler+  where+    -- | If any exception occurs, indicate that the monitor is not ready.+    errHandler :: CE.SomeException -> IO Bool+    errHandler _ = return False++    -- | Check for and indicate any errors in the http response.+    checkResult :: Status -> Bool+    checkResult status+        | statusIsServerError status = False+        | statusIsClientError status = False+        | otherwise = True++-- | Possibly create a new 'Manager', based upon the users preference.  If one+-- is created, this 'Manager' will be used throughout the monitor.+tryMakeManager :: WeatherOpts -> IO (Maybe Manager)+tryMakeManager opts =+    if useManager opts+        then Just <$> mkManager+        else pure Nothing++-- | Create a new 'Manager' for managing network connections.+mkManager :: IO Manager+mkManager = newManager $ tlsManagerSettings { managerConnCount = 1 }
src/Xmobar/Plugins/Monitors/Wireless.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE TypeApplications, CPP #-} ----------------------------------------------------------------------------- -- | -- Module      :  Plugins.Monitors.Wireless@@ -8,17 +9,69 @@ -- Stability   :  unstable -- Portability :  unportable ----- A monitor reporting ESSID and link quality for wireless interfaces+-- A monitor reporting SSID and signal level for wireless interfaces -- -----------------------------------------------------------------------------  module Xmobar.Plugins.Monitors.Wireless (wirelessConfig, runWireless)  where  import System.Console.GetOpt+import Data.Maybe (fromMaybe)  import Xmobar.Plugins.Monitors.Common++#ifdef IWLIB import Network.IWlib+#elif defined USE_NL80211+import Control.Exception (bracket)+import qualified Data.Map as M+import GHC.Int (Int8)+import Data.Maybe (listToMaybe)+import Control.Monad.IO.Class (liftIO)+import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)+import Data.ByteString.Char8 (unpack)+import Data.Serialize.Put (runPut, putWord32host, putByteString)+import Data.Serialize.Get (runGet) +import System.Linux.Netlink hiding (query)+import System.Linux.Netlink.GeNetlink.NL80211+import System.Linux.Netlink.GeNetlink.NL80211.StaInfo+import System.Linux.Netlink.GeNetlink.NL80211.Constants+import System.Posix.IO (closeFd)++data IwData = IwData { wiEssid :: String, wiSignal :: Maybe Int, wiQuality :: Int }++getWirelessInfo :: String -> IO IwData+getWirelessInfo ifname = do+  bracket makeNL80211Socket (closeFd . getFd) (\s -> do+  iflist <- getInterfaceList s+  iwdata <- runMaybeT $ do+    ifidx <- MaybeT . return $ foldr (\(n, i) z ->+                                       if (ifname == "" || ifname == n) then Just i else z)+                                     Nothing+                                     iflist+    scanp <- liftIO (getConnectedWifi s ifidx) >>=+             MaybeT . return . listToMaybe+    bssid <- MaybeT . return $ M.lookup eNL80211_ATTR_BSS (packetAttributes scanp) >>=+                               rightToMaybe . runGet getAttributes >>=+                               M.lookup eNL80211_BSS_BSSID+    stap <- liftIO (query s eNL80211_CMD_GET_STATION True $ M.fromList+                          [(eNL80211_ATTR_IFINDEX, runPut $ putWord32host ifidx),+                           (eNL80211_ATTR_MAC, runPut $ putByteString bssid)]) >>=+            MaybeT . return . listToMaybe+    let ssid   = fromMaybe "" $ getWifiAttributes scanp >>= M.lookup eWLAN_EID_SSID >>=+                                return . unpack+        signal = staInfoFromPacket stap >>= staSignalMBM >>=+                 return . fromIntegral @Int8 . fromIntegral+        qlty   = fromMaybe (-1) (round @Float . (/ 0.7) . (+ 110) .+                                                clamp (-110) (-40) . fromIntegral <$> signal)+    MaybeT . return $ Just $ IwData ssid signal qlty+  return $ fromMaybe (IwData "" Nothing (-1)) iwdata)+  where+    rightToMaybe = either (const Nothing) Just+    clamp lb up v = if v < lb then lb else if v > up then up else v+#endif+ newtype WirelessOpts = WirelessOpts   { qualityIconPattern :: Maybe IconPattern   }@@ -34,37 +87,43 @@      opts { qualityIconPattern = Just $ parseIconPattern d }) "") ""   ] -parseOpts :: [String] -> IO WirelessOpts-parseOpts argv =-  case getOpt Permute options argv of-       (o, _, []) -> return $ foldr id defaultOpts o-       (_, _, errs) -> ioError . userError $ concat errs- wirelessConfig :: IO MConfig wirelessConfig =-  mkMConfig "<essid> <quality>"-            ["essid", "quality", "qualitybar", "qualityvbar", "qualityipat"]+  mkMConfig "<ssid> <quality>"+            ["ssid", "essid", "signal", "quality", "qualitybar", "qualityvbar", "qualityipat"]  runWireless :: String -> [String] -> Monitor String runWireless iface args = do-  opts <- io $ parseOpts args+  opts <- io $ parseOptsWith options defaultOpts args+#ifdef IWLIB   iface' <- if "" == iface then io findInterface else return iface+#else+  let iface' = iface+#endif   wi <- io $ getWirelessInfo iface'   na <- getConfigValue naString   let essid = wiEssid wi       qlty = fromIntegral $ wiQuality wi       e = if essid == "" then na else essid   ep <- showWithPadding e+#ifdef USE_NL80211+  let s = wiSignal wi+#else+  let s = if qlty >= 0 then Just (qlty * 0.7 - 110) else Nothing+#endif+  sp <- showWithPadding $ maybe "" show s   q <- if qlty >= 0        then showPercentWithColors (qlty / 100)        else showWithPadding ""   qb <- showPercentBar qlty (qlty / 100)   qvb <- showVerticalBar qlty (qlty / 100)   qipat <- showIconPattern (qualityIconPattern opts) (qlty / 100)-  parseTemplate [ep, q, qb, qvb, qipat]+  parseTemplate [ep, ep, sp, q, qb, qvb, qipat] +#ifdef IWLIB findInterface :: IO String findInterface = do   c <- readFile "/proc/net/wireless"   let nds = lines c   return $ if length nds > 2 then takeWhile (/= 'c') (nds!!2) else []+#endif
src/Xmobar/Run/Command.hs view
@@ -41,7 +41,7 @@     start (Com p as al r) cb =       start (ComX p as ("Could not execute command " ++ p) al r) cb     start (ComX prog args msg _ r) cb = if r > 0 then go else exec-        where go = exec >> tenthSeconds r >> go+        where go = doEveryTenthSeconds r exec               exec = do                 (i,o,e,p) <- runInteractiveProcess prog args Nothing Nothing                 exit <- waitForProcess p
src/Xmobar/Run/Exec.hs view
@@ -17,23 +17,14 @@ -- ----------------------------------------------------------------------------- -module Xmobar.Run.Exec (Exec (..), tenthSeconds) where+module Xmobar.Run.Exec (Exec (..), tenthSeconds, doEveryTenthSeconds) where  import Prelude import Data.Char-import Control.Concurrent +import Xmobar.App.Timer (doEveryTenthSeconds, tenthSeconds) import Xmobar.System.Signal --- | Work around to the Int max bound: since threadDelay takes an Int, it--- is not possible to set a thread delay grater than about 45 minutes.--- With a little recursion we solve the problem.-tenthSeconds :: Int -> IO ()-tenthSeconds s | s >= x = do threadDelay (x * 100000)-                             tenthSeconds (s - x)-               | otherwise = threadDelay (s * 100000)-               where x = (maxBound :: Int) `div` 100000- class Show e => Exec e where     alias   :: e -> String     alias   e    = takeWhile (not . isSpace) $ show e@@ -43,6 +34,6 @@     run     _    = return ""     start   :: e -> (String -> IO ()) -> IO ()     start   e cb = go-        where go = run e >>= cb >> tenthSeconds (rate e) >> go+        where go = doEveryTenthSeconds (rate e) $ run e >>= cb     trigger :: e -> (Maybe SignalType -> IO ()) -> IO ()     trigger _ sh  = sh Nothing
src/Xmobar/X11/Draw.hs view
@@ -62,6 +62,8 @@                          (defaultDepthOfScreen (defaultScreenOfDisplay d)) #if XFT   when (alpha c /= 255) (liftIO $ drawBackground d p (bgColor c) (alpha c) wr)+#else+  _ <- return wr #endif   withColors d [bgColor c, borderColor c] $ \[bgcolor, bdcolor] -> do     gc <- liftIO $ createGC  d w
xmobar.cabal view
@@ -1,5 +1,5 @@ name:               xmobar-version:            0.32+version:            0.33 homepage:           http://xmobar.org synopsis:           A Minimalistic Text Based Status Bar description: 	    Xmobar is a minimalistic text based status bar.@@ -40,9 +40,13 @@   default: False  flag with_iwlib-  description: Wireless info support. Required for the Wireless plugin, needs iwlib installed.+  description: Wireless info support via Wext ioctls (deprecated). Required for the Wireless plugin, needs iwlib installed.   default: False +flag with_nl80211+  description: Wireless info support via nl80211. Required for the Wireless plugin on systems running Linux, the kernel.+  default: False+ flag with_mpd   description: MPD support. Needs libmpd installed.   default: False@@ -72,7 +76,7 @@   default: False  flag with_threaded-  description: Use threaded runtime.+  description: Use threaded runtime. Required for timer coalescing (less power usage).   default: False  flag with_rtsopts@@ -105,6 +109,7 @@                    Xmobar.App.Main,                    Xmobar.App.Opts,                    Xmobar.App.Compile,+                   Xmobar.App.Timer,                    Xmobar.System.Utils,                    Xmobar.System.StatFS,                    Xmobar.System.Environment,@@ -208,12 +213,19 @@        exposed-modules: Xmobar.Plugins.Mail, Xmobar.Plugins.MBox        cpp-options: -DINOTIFY -    if flag(with_iwlib) || flag(all_extensions)+    if flag(with_iwlib) || flag(with_nl80211) || flag(all_extensions)+       exposed-modules: Xmobar.Plugins.Monitors.Wireless++    if flag(with_iwlib)        extra-libraries: iw        build-depends: iwlib >= 0.1.0 && < 0.2-       exposed-modules: Xmobar.Plugins.Monitors.Wireless        cpp-options: -DIWLIB +    if !flag(with_iwlib) && (flag(with_nl80211) || flag(all_extensions))+       build-depends: netlink >= 1.1.1.0,+                      cereal >= 0.5.8.1+       cpp-options: -DUSE_NL80211+     if flag(with_mpd) || flag(all_extensions)        build-depends: libmpd >= 0.9.0.10        exposed-modules: Xmobar.Plugins.Monitors.MPD@@ -257,6 +269,11 @@        build-depends: http-conduit, http-types        cpp-options: -DUVMETER +    if os(freebsd)+       -- enables freebsd specific code+       build-depends: bsd-sysctl+       cpp-options: -DFREEBSD+ executable xmobar     hs-source-dirs:     app     main-is:            Main.hs@@ -315,6 +332,7 @@                  Xmobar.Plugins.Monitors.Common.Output                  Xmobar.Plugins.Monitors.Common.Files                  Xmobar.Run.Exec+                 Xmobar.App.Timer                  Xmobar.System.Signal    if flag(with_alsa) || flag(all_extensions)