xmobar 0.33 → 0.34
raw patch · 27 files changed
+293/−165 lines, 27 filesdep +http-client-tlsdep ~basedep ~bytestring
Dependencies added: http-client-tls
Dependency ranges changed: base, bytestring
Files
- changelog.md +13/−0
- readme.md +33/−13
- src/Xmobar.hs +2/−0
- src/Xmobar/App/EventLoop.hs +4/−2
- src/Xmobar/App/Main.hs +2/−1
- src/Xmobar/App/Opts.hs +4/−4
- src/Xmobar/Plugins/BufferedPipeReader.hs +1/−2
- src/Xmobar/Plugins/CommandReader.hs +1/−2
- src/Xmobar/Plugins/Date.hs +11/−3
- src/Xmobar/Plugins/HandleReader.hs +70/−0
- src/Xmobar/Plugins/MarqueePipeReader.hs +3/−4
- src/Xmobar/Plugins/Monitors/MPD.hs +17/−11
- src/Xmobar/Plugins/Monitors/Net.hs +6/−3
- src/Xmobar/Plugins/Monitors/UVMeter.hs +10/−30
- src/Xmobar/Plugins/Monitors/Volume.hs +2/−4
- src/Xmobar/Plugins/Monitors/Weather.hs +10/−29
- src/Xmobar/Plugins/Monitors/Wireless.hs +13/−8
- src/Xmobar/Plugins/PipeReader.hs +1/−2
- src/Xmobar/Plugins/StdinReader.hs +15/−8
- src/Xmobar/Run/Command.hs +2/−3
- src/Xmobar/Run/Exec.hs +1/−1
- src/Xmobar/System/Utils.hs +33/−16
- src/Xmobar/X11/Draw.hs +6/−4
- src/Xmobar/X11/Parsers.hs +3/−1
- src/Xmobar/X11/Types.hs +2/−1
- test/Xmobar/Plugins/Monitors/AlsaSpec.hs +11/−0
- xmobar.cabal +17/−13
changelog.md view
@@ -1,3 +1,16 @@+## Version 0.34 (June, 2020)++_New features_++ - New plugin `HandleReader` for reading data from a Haskell `Handle`. This is+ useful if you are running xmobar from within a Haskell program.+ - Build with ghc 8.10 allowed.+ - Optimize date plugin by avoiding calling getTimeZone for each of+ the time the date has to be updated. Instead, it's computed once+ at the start and re-used for each invocation.+ - Optimize Weather and UVMeter plugin by using global Manager instead of+ creating for each http request when useManager is explicitly configured as False.+ ## Version 0.33 (February, 2020) _New features_
readme.md view
@@ -798,11 +798,14 @@ - Args: default monitor arguments, plus: - `--rx-icon-pattern`: dynamic string for reception rate in `rxipat`. - `--tx-icon-pattern`: dynamic string for transmission rate in `txipat`.+ - `--up`: string used for the `up` variable value when the+ interface is up. - Variables that can be used with the `-t`/`--template` argument: `dev`, `rx`, `tx`, `rxbar`, `rxvbar`, `rxipat`, `txbar`, `txvbar`,- `txipat`. Reception and transmission rates (`rx` and `tx`) are displayed- by default as Kb/s, without any suffixes, but you can set the `-S` to- "True" to make them displayed with adaptive units (Kb/s, Mb/s, etc.).+ `txipat`, `up`. Reception and transmission rates (`rx` and `tx`) are+ displayed by default as Kb/s, without any suffixes, but you can set+ the `-S` to "True" to make them displayed with adaptive units (Kb/s,+ Mb/s, etc.). - Default template: `<dev>: <rx>KB|<tx>KB` ### `DynNetwork Args RefreshRate`@@ -1147,7 +1150,7 @@ Run MultiCoreTemp ["-t", "Temp: <avg>°C | <avgpc>%", "-L", "60", "-H", "80",- "-l", "green", "-n", "yellow", "-h", "red"+ "-l", "green", "-n", "yellow", "-h", "red", "--", "--mintemp", "20", "--maxtemp", "100"] 50 ### `Volume Mixer Element Args RefreshRate`@@ -1610,6 +1613,23 @@ logHook = dynamicLogString myPP >>= xmonadPropLog } +### `HandleReader Handle Alias`++- Display data from a Haskell `Handle`+- This plugin is only useful if you are running xmobar from another Haskell+ program like XMonad.+- You can use `System.Process.createPipe` to create a pair of `read` & `write`+ Handles. Pass the `read` Handle to HandleReader and write your output to the+ `write` Handle:++ (readHandle, writeHandle) <- createPipe+ xmobarProcess <- forkProcess $ xmobar myConfig+ { commands =+ Run (HandleReader readHandle "handle") : commands myConfig+ }+ hPutStr writeHandle "Hello World"++ # Plugins ## Writing a Plugin@@ -1697,14 +1717,14 @@ 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.+Jens Petersen, Alexander Polakov, Sibi Prabakaran, 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. [jao]: http://jao.io [incorporates patches]: http://www.ohloh.net/p/xmobar/contributors@@ -1741,7 +1761,7 @@ This software is released under a BSD-style license. See [LICENSE] for more details. -Copyright © 2010-2019 Jose Antonio Ortega Ruiz+Copyright © 2010-2020 Jose Antonio Ortega Ruiz Copyright © 2007-2010 Andrea Rossato
src/Xmobar.hs view
@@ -32,6 +32,7 @@ , module Xmobar.Plugins.DateZone #endif , module Xmobar.Plugins.EWMH+ , module Xmobar.Plugins.HandleReader , module Xmobar.Plugins.Kbd , module Xmobar.Plugins.Locks #ifdef INOTIFY@@ -57,6 +58,7 @@ import Xmobar.Plugins.DateZone #endif import Xmobar.Plugins.EWMH+import Xmobar.Plugins.HandleReader import Xmobar.Plugins.Kbd import Xmobar.Plugins.Locks #ifdef INOTIFY
src/Xmobar/App/EventLoop.hs view
@@ -40,6 +40,7 @@ import Data.Bits import Data.Map hiding (foldr, map, filter) import Data.Maybe (fromJust, isJust)+import qualified Data.List.NonEmpty as NE import Xmobar.System.Signal import Xmobar.Config.Types@@ -52,6 +53,7 @@ import Xmobar.X11.Draw import Xmobar.X11.Bitmap as Bitmap import Xmobar.X11.Types+import Xmobar.System.Utils (safeIndex) #ifndef THREADED_RUNTIME import Xmobar.X11.Events(nextEvent')@@ -208,7 +210,7 @@ eventLoop tv xc as signal reposWindow rcfg = do- r' <- repositionWin d w (head fs) rcfg+ r' <- repositionWin d w (NE.head fs) rcfg eventLoop tv (XConf d r' w fs vos is rcfg) as signal updateConfigPosition ocfg =@@ -262,7 +264,7 @@ strLn :: [(Widget, String, Int, Maybe [Action])] -> IO [(Maybe [Action], Position, Position)] strLn = liftIO . mapM getCoords iconW i = maybe 0 Bitmap.width (lookup i $ iconS conf)- getCoords (Text s,_,i,a) = textWidth d (fs!!i) s >>= \tw -> return (a, 0, fi tw)+ getCoords (Text s,_,i,a) = textWidth d (safeIndex fs i) s >>= \tw -> return (a, 0, fi tw) getCoords (Icon s,_,_,a) = return (a, 0, fi $ iconW s) partCoord off xs = map (\(a, x, x') -> (fromJust a, x, x')) $ filter (\(a, _,_) -> isJust a) $
src/Xmobar/App/Main.hs view
@@ -29,6 +29,7 @@ import System.FilePath import System.FilePath.Posix (takeBaseName, takeDirectory) import Text.Parsec.Error (ParseError)+import Data.List.NonEmpty (NonEmpty(..)) import Graphics.X11.Xlib @@ -63,7 +64,7 @@ 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+ 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/Opts.hs view
@@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.App.Opts--- Copyright: (c) 2018, 2019 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2018, 2019, 2020 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org@@ -104,9 +104,9 @@ info :: String info = "xmobar " ++ showVersion version- ++ "\n (C) 2007 - 2010 Andrea Rossato "- ++ "\n (C) 2010 - 2019 Jose A Ortega Ruiz\n "- ++ mail ++ "\n" ++ license+ ++ "\n (C) 2010 - 2020 Jose A Ortega Ruiz"+ ++ "\n (C) 2007 - 2010 Andrea Rossato\n "+ ++ mail ++ "\n" ++ license ++ "\n" mail :: String mail = "<mail@jao.io>"
src/Xmobar/Plugins/BufferedPipeReader.hs view
@@ -23,7 +23,6 @@ import Xmobar.Run.Exec import Xmobar.System.Signal import Xmobar.System.Environment-import Xmobar.System.Utils(hGetLineSafe) data BufferedPipeReader = BufferedPipeReader String [(Int, Bool, String)] deriving (Read, Show)@@ -55,7 +54,7 @@ reader :: (Int, Bool, FilePath) -> TChan (Int, Bool, String) -> IO () reader p@(to, tg, fp) tc = do fp' <- expandEnv fp- openFile fp' ReadWriteMode >>= hGetLineSafe >>= \dt ->+ openFile fp' ReadWriteMode >>= hGetLine >>= \dt -> atomically $ writeTChan tc (to, tg, dt) reader p tc
src/Xmobar/Plugins/CommandReader.hs view
@@ -17,7 +17,6 @@ import System.IO import Xmobar.Run.Exec-import Xmobar.System.Utils (hGetLineSafe) import System.Process(runInteractiveCommand, getProcessExitCode) data CommandReader = CommandReader String String@@ -31,7 +30,7 @@ hClose hstderr hSetBinaryMode hstdout False hSetBuffering hstdout LineBuffering- forever ph (hGetLineSafe hstdout >>= cb)+ forever ph (hGetLine hstdout >>= cb) where forever ph a = do a ec <- getProcessExitCode ph
src/Xmobar/Plugins/Date.hs view
@@ -31,8 +31,16 @@ instance Exec Date where alias (Date _ a _) = a- run (Date f _ _) = date f rate (Date _ _ r) = r+ start (Date f _ r) cb = do+ t <- getCurrentTime+ zone <- getTimeZone t+ go zone+ where+ go zone = doEveryTenthSeconds r $ date zone f >>= cb -date :: String -> IO String-date format = fmap (formatTime defaultTimeLocale format) getZonedTime+date :: TimeZone -> String -> IO String+date timezone format = do+ time <- getCurrentTime+ let zonedTime = utcToZonedTime timezone time+ pure $ formatTime defaultTimeLocale format zonedTime
+ src/Xmobar/Plugins/HandleReader.hs view
@@ -0,0 +1,70 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.HandleReader+-- Copyright : (c) Pavan Rikhi+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Pavan Rikhi <pavan.rikhi@gmail.com>+-- Stability : unstable+-- Portability : portable+--+-- A plugin for reading from 'Handle's+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.HandleReader+ ( HandleReader(..)+ )+where++import System.IO ( Handle+ , hIsEOF+ , hGetLine+ )++import Xmobar.Run.Exec ( Exec(..) )+++-- | A HandleReader displays any text received from a Handle.+--+-- This is only useful if you are running @xmobar@ from other Haskell code.+-- You can create a pair of @(read, write)@ 'Handle's using+-- 'System.Process.createPipe'. Pass the @read@ 'Handle' to HandleReader+-- and write your desired output to the @write@ 'Handle'.+--+-- @+-- (readHandle, writeHandle) <- 'System.Process.createPipe'+-- xmobarProcess <- 'System.Posix.Process.forkProcess' $ 'Xmobar.xmobar' myConfig+-- { commands =+-- 'Xmobar.Run' ('HandleReader' readHandle "handle") : 'Xmobar.commands' myConfig+-- }+-- 'System.IO.hPutStr' writeHandle "Hello World"+-- @+data HandleReader+ = HandleReader+ Handle+ -- ^ The Handle to read from.+ String+ -- ^ Alias for the HandleReader+ deriving (Show)++-- | WARNING: This Read instance will throw an exception if used! It is+-- only implemented because it is required to use HandleReader with+-- 'Xmobar.Run' in 'Xmobar.commands'.+instance Read HandleReader where+ -- | Throws an 'error'!+ readsPrec = error "HandleReader: Read instance is stub"++-- | Asynchronously read from the 'Handle'.+instance Exec HandleReader where+ -- | Read from the 'Handle' until it is closed.+ start (HandleReader handle _) cb =+ untilM (hIsEOF handle) $ hGetLine handle >>= cb+ -- | Use the 2nd argument to HandleReader as its alias.+ alias (HandleReader _ a) = a++-- Loop the action until predicateM returns True.+untilM :: Monad m => m Bool -> m () -> m ()+untilM predicateM action = do+ predicate <- predicateM+ if predicate then return () else action >> untilM predicateM action
src/Xmobar/Plugins/MarqueePipeReader.hs view
@@ -14,10 +14,9 @@ module Xmobar.Plugins.MarqueePipeReader(MarqueePipeReader(..)) where -import System.IO (openFile, IOMode(ReadWriteMode), Handle)+import System.IO (openFile, IOMode(ReadWriteMode), Handle, hGetLine) import Xmobar.System.Environment import Xmobar.Run.Exec(Exec(alias, start), tenthSeconds)-import Xmobar.System.Utils(hGetLineSafe) import System.Posix.Files (getFileStatus, isNamedPipe) import Control.Concurrent(forkIO, threadDelay) import Control.Concurrent.STM (TChan, atomically, writeTChan, tryReadTChan, newTChan)@@ -39,7 +38,7 @@ unless (null def) (cb def) checkPipe pipe h <- openFile pipe ReadWriteMode- line <- hGetLineSafe h+ line <- hGetLine h chan <- atomically newTChan forkIO $ writer (toInfTxt line sep) sep len rate chan cb forever $ pipeToChan h chan@@ -50,7 +49,7 @@ pipeToChan :: Handle -> TChan String -> IO () pipeToChan h chan = do- line <- hGetLineSafe h+ line <- hGetLine h atomically $ writeTChan chan line writer :: String -> Separator -> Length -> Rate -> TChan String -> (String -> IO ()) -> IO ()
src/Xmobar/Plugins/Monitors/MPD.hs view
@@ -20,14 +20,17 @@ import System.Console.GetOpt import qualified Network.MPD as M import Control.Concurrent (threadDelay)+import Control.Monad.Except (catchError) +templateVars :: [String]+templateVars = [ "bar", "vbar", "ipat", "state", "statei", "volume", "length"+ , "lapsed", "remaining", "plength", "ppos", "flags", "file"+ , "name", "artist", "composer", "performer"+ , "album", "title", "track", "genre", "date"+ ]+ mpdConfig :: IO MConfig-mpdConfig = mkMConfig "MPD: <state>"- [ "bar", "vbar", "ipat", "state", "statei", "volume", "length"- , "lapsed", "remaining", "plength", "ppos", "flags", "file"- , "name", "artist", "composer", "performer"- , "album", "title", "track", "genre", "date"- ]+mpdConfig = mkMConfig "MPD: <state>" templateVars data MOpts = MOpts { mPlaying :: String@@ -60,7 +63,8 @@ ] withMPD :: MOpts -> M.MPD a -> IO (M.Response a)-withMPD opts = M.withMPD_ (mHost opts) (mPort opts)+withMPD opts a =+ M.withMPD_ (mHost opts) (mPort opts) a `catchError` (\_ -> return (Left M.NoMPD)) runMPD :: [String] -> Monitor String runMPD args = do@@ -74,7 +78,7 @@ mpdWait = do status <- M.withMPD $ M.idle [M.PlayerS, M.MixerS, M.OptionsS] case status of- Left _ -> threadDelay 10000000+ Left _ -> threadDelay 5000 _ -> return () mpdReady :: [String] -> Monitor Bool@@ -91,19 +95,21 @@ parseMPD :: M.Response M.Status -> M.Response (Maybe M.Song) -> MOpts -> Monitor [String]-parseMPD (Left e) _ _ = return $ show e:replicate 19 ""+parseMPD (Left _) _ _ = return $ "N/A": repeat "" parseMPD (Right st) song opts = do songData <- parseSong song bar <- showPercentBar (100 * b) b vbar <- showVerticalBar (100 * b) b ipat <- showIconPattern (mLapsedIconPattern opts) b- return $ [bar, vbar, ipat, ss, si, vol, len, lap, remain, plen, ppos, flags] ++ songData+ return $ [bar, vbar, ipat, ss, si, vol, len, lap, remain, plen, ppos, flags]+ ++ songData where s = M.stState st ss = show s si = stateGlyph s opts vol = int2str $ fromMaybe 0 (M.stVolume st) (p, t) = fromMaybe (0, 0) (M.stTime st)- [lap, len, remain] = map showTime [floor p, floor t, max 0 (floor t - floor p)]+ [lap, len, remain] = map showTime+ [floor p, floor t, max 0 (floor t - floor p)] b = if t > 0 then realToFrac $ p / t else 0 plen = int2str $ M.stPlaylistLength st ppos = maybe "" (int2str . (+1)) $ M.stSongPos st
src/Xmobar/Plugins/Monitors/Net.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Net--- Copyright : (c) 2011, 2012, 2013, 2014, 2017 Jose Antonio Ortega Ruiz+-- Copyright : (c) 2011, 2012, 2013, 2014, 2017, 2020 Jose Antonio Ortega Ruiz -- (c) 2007-2010 Andrea Rossato -- License : BSD-style (see LICENSE) --@@ -49,6 +49,7 @@ { rxIconPattern :: Maybe IconPattern , txIconPattern :: Maybe IconPattern , onlyDevList :: Maybe DevList+ , upIndicator :: String } defaultOpts :: NetOpts@@ -56,6 +57,7 @@ { rxIconPattern = Nothing , txIconPattern = Nothing , onlyDevList = Nothing+ , upIndicator = "+" } options :: [OptDescr (NetOpts -> NetOpts)]@@ -64,6 +66,7 @@ o { rxIconPattern = Just $ parseIconPattern x }) "") "" , Option "" ["tx-icon-pattern"] (ReqArg (\x o -> o { txIconPattern = Just $ parseIconPattern x }) "") ""+ , Option "" ["up"] (ReqArg (\x o -> o { upIndicator = x }) "") "" , Option "" ["devices"] (ReqArg (\x o -> o { onlyDevList = Just $ parseDevList x }) "") "" ]@@ -103,7 +106,7 @@ netConfig :: IO MConfig netConfig = mkMConfig "<dev>: <rx>KB|<tx>KB" -- template- ["dev", "rx", "tx", "rxbar", "rxvbar", "rxipat", "txbar", "txvbar", "txipat"] -- available replacements+ ["dev", "rx", "tx", "rxbar", "rxvbar", "rxipat", "txbar", "txvbar", "txipat", "up"] -- available replacements operstateDir :: String -> FilePath operstateDir d = "/sys/class/net" </> d </> "operstate"@@ -160,7 +163,7 @@ N d (ND r t) -> do (rx, rb, rvb, ripat) <- formatNet (rxIconPattern opts) r (tx, tb, tvb, tipat) <- formatNet (txIconPattern opts) t- parseTemplate [d,rx,tx,rb,rvb,ripat,tb,tvb,tipat]+ parseTemplate [d,rx,tx,rb,rvb,ripat,tb,tvb,tipat, upIndicator opts] N _ NI -> return "" NA -> getConfigValue naString
src/Xmobar/Plugins/Monitors/UVMeter.hs view
@@ -21,14 +21,11 @@ import Network.HTTP.Conduit ( Manager , httpLbs- , managerConnCount- , newManager , parseRequest , responseBody- , tlsManagerSettings )+import Network.HTTP.Client.TLS (getGlobalManager) 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@@ -66,12 +63,9 @@ uvURL = "https://uvdata.arpansa.gov.au/xml/uvvalues.xml" -- | 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+getData ::Manager -> IO String+getData man = CE.catch+ (do request <- parseRequest uvURL res <- httpLbs request man return $ B.unpack $ responseBody res) errHandler@@ -105,15 +99,13 @@ -> 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+startUVMeter station args = runM (station : args) uvConfig runUVMeter -runUVMeter :: Maybe Manager -> [String] -> Monitor String-runUVMeter _ [] = return "N.A."-runUVMeter uvMan (s:_) = do- resp <- io $ getData uvMan+runUVMeter :: [String] -> Monitor String+runUVMeter [] = return "N.A."+runUVMeter (s:_) = do+ man <- io getGlobalManager+ resp <- io $ getData man case textToXMLDocument resp of Right doc -> formatUVRating (getUVRating s doc) Left _ -> getConfigValue naString@@ -195,15 +187,3 @@ 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
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Volume--- Copyright : (c) 2011, 2013, 2015, 2018 Thomas Tuegel+-- Copyright : (c) 2011, 2013, 2015, 2018, 2020 Thomas Tuegel -- License : BSD-style (see LICENSE) -- -- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>@@ -23,7 +23,6 @@ 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@@ -257,6 +256,5 @@ -- | Determine whether the volume is off based on the value of 'sw' from -- 'runVolumeWith'.- isVolOff = not . fromMaybe False-+ isVolOff = (Just True /=) unavailable = getConfigValue naString
src/Xmobar/Plugins/Monitors/Weather.hs view
@@ -21,33 +21,30 @@ 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 Network.HTTP.Client.TLS (getGlobalManager) import Text.ParserCombinators.Parsec import System.Console.GetOpt (ArgDescr(ReqArg), OptDescr(Option)) -- | Options the user may specify.-data WeatherOpts = WeatherOpts+newtype 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@@ -213,12 +210,10 @@ stationUrl station = defUrl ++ station ++ ".TXT" -- | 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+getData :: String -> IO String+getData station = CE.catch+ (do request <- parseUrlThrow $ stationUrl station+ man <- getGlobalManager res <- httpLbs request man return $ B.unpack $ responseBody res) errHandler@@ -261,11 +256,10 @@ -> 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)+ (runWeather sks opts) rate weatherReady cb@@ -278,12 +272,11 @@ -- | 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)+runWeather sks opts args = do+ d <- io $ getData (head args) i <- io $ runP parseData d formatWeather opts sks i @@ -293,7 +286,7 @@ let request = initRequest { method = methodHead } CE.catch- (do man <- mkManager+ (do man <- getGlobalManager res <- httpLbs request man return $ checkResult $ responseStatus res) errHandler@@ -308,15 +301,3 @@ | 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,4 +1,7 @@-{-# LANGUAGE TypeApplications, CPP #-}+{-# LANGUAGE CPP #-}+#ifdef USE_NL80211+{-# LANGUAGE TypeApplications #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Wireless@@ -16,7 +19,6 @@ module Xmobar.Plugins.Monitors.Wireless (wirelessConfig, runWireless) where import System.Console.GetOpt-import Data.Maybe (fromMaybe) import Xmobar.Plugins.Monitors.Common @@ -26,7 +28,7 @@ import Control.Exception (bracket) import qualified Data.Map as M import GHC.Int (Int8)-import Data.Maybe (listToMaybe)+import Data.Maybe (listToMaybe, fromMaybe) import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT) import Data.ByteString.Char8 (unpack)@@ -42,12 +44,12 @@ data IwData = IwData { wiEssid :: String, wiSignal :: Maybe Int, wiQuality :: Int } getWirelessInfo :: String -> IO IwData-getWirelessInfo ifname = do+getWirelessInfo ifname = 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)+ if ifname == "" || ifname == n then Just i else z) Nothing iflist scanp <- liftIO (getConnectedWifi s ifidx) >>=@@ -63,13 +65,16 @@ return . unpack signal = staInfoFromPacket stap >>= staSignalMBM >>= return . fromIntegral @Int8 . fromIntegral- qlty = fromMaybe (-1) (round @Float . (/ 0.7) . (+ 110) .- clamp (-110) (-40) . fromIntegral <$> signal)+ qlty = maybe (-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+ clamp lb up v+ | v < lb = lb+ | v > up = up+ | otherwise = v #endif newtype WirelessOpts = WirelessOpts
src/Xmobar/Plugins/PipeReader.hs view
@@ -16,7 +16,6 @@ import System.IO import Xmobar.Run.Exec(Exec(..))-import Xmobar.System.Utils(hGetLineSafe) import Xmobar.System.Environment(expandEnv) import System.Posix.Files import Control.Concurrent(threadDelay)@@ -34,7 +33,7 @@ unless (null def) (cb def) checkPipe pipe h <- openFile pipe ReadWriteMode- forever (hGetLineSafe h >>= cb)+ forever (hGetLine h >>= cb) where split c xs | c `elem` xs = let (pre, post) = span (c /=) xs in (pre, dropWhile (c ==) post)
src/Xmobar/Plugins/StdinReader.hs view
@@ -22,23 +22,30 @@ import System.Posix.Process import System.Exit import System.IO-import Control.Exception (SomeException(..), handle) import Xmobar.Run.Exec import Xmobar.X11.Actions (stripActions)-import Xmobar.System.Utils (hGetLineSafe)+import Xmobar.System.Utils (onSomeException)+import Control.Monad (when) data StdinReader = StdinReader | UnsafeStdinReader deriving (Read, Show) instance Exec StdinReader where start stdinReader cb = do- s <- handle (\(SomeException e) -> do hPrint stderr e; return "")- (hGetLineSafe stdin)- cb $ escape stdinReader s+ -- The EOF check is necessary for certain systems+ -- More details here https://github.com/jaor/xmobar/issues/442 eof <- isEOF- if eof- then exitImmediately ExitSuccess- else start stdinReader cb+ when eof $+ do hPrint stderr "xmobar: eof at an early stage"+ exitImmediately ExitSuccess+ s <-+ getLine `onSomeException`+ (\e -> do+ let errorMessage = "xmobar: Received exception " <> show e+ hPrint stderr errorMessage+ cb errorMessage)+ cb $ escape stdinReader s+ start stdinReader cb escape :: StdinReader -> String -> String escape StdinReader = stripActions
src/Xmobar/Run/Command.hs view
@@ -20,8 +20,7 @@ import Control.Exception (handle, SomeException(..)) import System.Process import System.Exit-import System.IO (hClose)-import Xmobar.System.Utils (hGetLineSafe)+import System.IO (hClose, hGetLine) import Xmobar.Run.Exec @@ -47,7 +46,7 @@ exit <- waitForProcess p let closeHandles = hClose o >> hClose i >> hClose e getL = handle (\(SomeException _) -> return "")- (hGetLineSafe o)+ (hGetLine o) case exit of ExitSuccess -> do str <- getL closeHandles
src/Xmobar/Run/Exec.hs view
@@ -10,7 +10,7 @@ -- -- The 'Exec' class and the 'Command' data type. ----- The 'Exec' class rappresents the executable types, whose constructors may+-- The 'Exec' class represents the executable types, whose constructors may -- appear in the 'Config.commands' field of the 'Config.Config' data type. -- -- The 'Command' data type is for OS commands to be run by xmobar
src/Xmobar/System/Utils.hs view
@@ -3,7 +3,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Utils--- Copyright: (c) 2010, 2018 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2010, 2018, 2020 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: Jose A Ortega Ruiz <jao@gnu.org>@@ -17,27 +17,21 @@ ------------------------------------------------------------------------------ -module Xmobar.System.Utils (expandHome, changeLoop, hGetLineSafe)-where+module Xmobar.System.Utils+ ( expandHome+ , changeLoop+ , onSomeException+ , safeIndex+ ) where import Control.Monad import Control.Concurrent.STM+import qualified Data.List.NonEmpty as NE+import Data.Maybe (fromMaybe) import System.Environment import System.FilePath-import System.IO--#if defined XFT || defined UTF8-import qualified System.IO as S (hGetLine)-#endif--hGetLineSafe :: Handle -> IO String-#if defined XFT || defined UTF8-hGetLineSafe = S.hGetLine-#else-hGetLineSafe = hGetLine-#endif-+import Control.Exception expandHome :: FilePath -> IO FilePath expandHome ('~':'/':path) = fmap (</> path) (getEnv "HOME")@@ -52,3 +46,26 @@ new <- s guard (new /= old) return new)++-- | Like 'finally', but only performs the final action if there was an+-- exception raised by the computation.+--+-- Note that this implementation is a slight modification of+-- onException function.+onSomeException :: IO a -> (SomeException -> IO b) -> IO a+onSomeException io what = io `catch` \e -> do _ <- what e+ throwIO (e :: SomeException)++(!!?) :: [a] -> Int -> Maybe a+(!!?) xs i+ | i < 0 = Nothing+ | otherwise = go i xs+ where+ go :: Int -> [a] -> Maybe a+ go 0 (x:_) = Just x+ go j (_:ys) = go (j - 1) ys+ go _ [] = Nothing+{-# INLINE (!!?) #-}++safeIndex :: NE.NonEmpty a -> Int -> a+safeIndex xs index = fromMaybe (NE.head xs) (NE.toList xs !!? index)
src/Xmobar/X11/Draw.hs view
@@ -25,6 +25,7 @@ import Control.Monad (when) import Control.Arrow ((&&&)) import Data.Map hiding (foldr, map, filter)+import qualified Data.List.NonEmpty as NE import Graphics.X11.Xlib hiding (textExtents, textWidth) import Graphics.X11.Xlib.Extras@@ -37,6 +38,7 @@ import Xmobar.X11.ColorCache import Xmobar.X11.Window (drawBorder) import Xmobar.X11.Parsers (Widget(..))+import Xmobar.System.Utils (safeIndex) #ifdef XFT import Xmobar.X11.MinXft@@ -55,7 +57,7 @@ strLn = liftIO . mapM getWidth iconW i = maybe 0 B.width (lookup i $ iconS r) getWidth (Text s,cl,i,_) =- textWidth d (fs!!i) s >>= \tw -> return (Text s,cl,i,fi tw)+ textWidth d (safeIndex fs i) s >>= \tw -> return (Text s,cl,i,fi tw) getWidth (Icon s,cl,i,_) = return (Icon s,cl,i,fi $ iconW s) p <- liftIO $ createPixmap d w wid ht@@ -126,7 +128,7 @@ #endif -- | An easy way to print the stuff we need to print-printStrings :: Drawable -> GC -> [XFont] -> [Int] -> Position+printStrings :: Drawable -> GC -> NE.NonEmpty XFont -> [Int] -> Position -> Align -> [(Widget, String, Int, Position)] -> X () printStrings _ _ _ _ _ _ [] = return () printStrings dr gc fontlist voffs offs a sl@((s,c,i,l):xs) = do@@ -136,7 +138,7 @@ Rectangle _ _ wid ht = rect r totSLen = foldr (\(_,_,_,len) -> (+) len) 0 sl remWidth = fi wid - fi totSLen- fontst = fontlist !! i+ fontst = safeIndex fontlist i offset = case a of C -> (remWidth + offs) `div` 2 R -> remWidth@@ -144,7 +146,7 @@ (fc,bc) = case break (==',') c of (f,',':b) -> (f, b ) (f, _) -> (f, bgColor conf)- valign <- verticalOffset ht s (head fontlist) (voffs !! i) conf+ valign <- verticalOffset ht s (NE.head fontlist) (voffs !! i) conf case s of (Text t) -> liftIO $ printString d dr fontst gc fc bc offset valign t alph (Icon p) -> liftIO $ maybe (return ())
src/Xmobar/X11/Parsers.hs view
@@ -20,7 +20,9 @@ import Xmobar.X11.Actions import Control.Monad (guard, mzero)+import Data.Maybe (fromMaybe) import Text.ParserCombinators.Parsec+import Text.Read (readMaybe) import Graphics.X11.Types (Button) data Widget = Icon String | Text String@@ -138,7 +140,7 @@ -> Parser [(Widget, ColorString, FontIndex, Maybe [Action])] fontParser c a = do f <- between (string "<fn=") (string ">") colors- s <- manyTill (allParsers c (read f) a) (try $ string "</fn>")+ s <- manyTill (allParsers c (fromMaybe 0 $ readMaybe f) a) (try $ string "</fn>") return (concat s) -- | Parses a color specification (hex or named)
src/Xmobar/X11/Types.hs view
@@ -20,6 +20,7 @@ import Graphics.X11.Xlib import Control.Monad.Reader import Data.Map+import qualified Data.List.NonEmpty as NE import Xmobar.X11.Bitmap import Xmobar.X11.Text@@ -33,7 +34,7 @@ XConf { display :: Display , rect :: Rectangle , window :: Window- , fontListS :: [XFont]+ , fontListS :: NE.NonEmpty XFont , verticalOffsets :: [Int] , iconS :: Map FilePath Bitmap , config :: Config
test/Xmobar/Plugins/Monitors/AlsaSpec.hs view
@@ -1,9 +1,12 @@ {-# OPTIONS_GHC -Wall #-}+{-# LANGUAGE CPP #-}+ module Xmobar.Plugins.Monitors.AlsaSpec ( main , spec ) where +#ifdef ALSA import Control.Concurrent import Control.Concurrent.Async import Control.Monad@@ -158,3 +161,11 @@ $ \(Just h) _ _ _ -> do hSetBuffering h LineBuffering body h+#else+-- These No-Op values are required for HSpec's test discovery.+main :: IO ()+main = return ()++spec :: Monad m => m ()+spec = return ()+#endif
xmobar.cabal view
@@ -1,5 +1,5 @@ name: xmobar-version: 0.33+version: 0.34 homepage: http://xmobar.org synopsis: A Minimalistic Text Based Status Bar description: Xmobar is a minimalistic text based status bar.@@ -13,7 +13,7 @@ author: Andrea Rossato and Jose A. Ortega Ruiz maintainer: Jose A. Ortega Ruiz <jao@gnu.org> bug-reports: https://github.com/jaor/xmobar/issues-cabal-version: >= 1.8+cabal-version: >= 1.10 build-type: Simple extra-source-files: readme.md, changelog.md,@@ -92,6 +92,7 @@ default: True library+ default-language: Haskell2010 hs-source-dirs: src exposed-modules: Xmobar@@ -129,6 +130,7 @@ Xmobar.Plugins.CommandReader, Xmobar.Plugins.Date, Xmobar.Plugins.EWMH,+ Xmobar.Plugins.HandleReader, Xmobar.Plugins.PipeReader, Xmobar.Plugins.MarqueePipeReader, Xmobar.Plugins.StdinReader,@@ -164,12 +166,12 @@ ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind build-depends:- base >= 4.9.1.0 && < 4.14,+ base >= 4.9.1.0 && < 4.15, containers, regex-compat, process, old-locale,- bytestring,+ bytestring >= 0.10.8.2, directory, unix, time,@@ -210,11 +212,11 @@ if flag(with_inotify) || flag(all_extensions) build-depends: hinotify >= 0.3 && < 0.5- exposed-modules: Xmobar.Plugins.Mail, Xmobar.Plugins.MBox+ other-modules: Xmobar.Plugins.Mail, Xmobar.Plugins.MBox cpp-options: -DINOTIFY if flag(with_iwlib) || flag(with_nl80211) || flag(all_extensions)- exposed-modules: Xmobar.Plugins.Monitors.Wireless+ other-modules: Xmobar.Plugins.Monitors.Wireless if flag(with_iwlib) extra-libraries: iw@@ -228,25 +230,25 @@ if flag(with_mpd) || flag(all_extensions) build-depends: libmpd >= 0.9.0.10- exposed-modules: Xmobar.Plugins.Monitors.MPD+ other-modules: Xmobar.Plugins.Monitors.MPD cpp-options: -DLIBMPD if flag(with_alsa) || flag(all_extensions) build-depends: alsa-mixer >= 0.3 && < 0.4 build-depends: alsa-core == 0.5.*, process >= 1.4.3.0- exposed-modules: Xmobar.Plugins.Monitors.Volume+ other-modules: Xmobar.Plugins.Monitors.Volume Xmobar.Plugins.Monitors.Alsa cpp-options: -DALSA if flag(with_datezone) || flag(all_extensions) build-depends: timezone-olson == 0.1.*, timezone-series == 0.1.*- exposed-modules: Xmobar.Plugins.DateZone+ other-modules: Xmobar.Plugins.DateZone cpp-options: -DDATEZONE if flag(with_mpris) || flag(all_extensions) build-depends: dbus >= 1- exposed-modules: Xmobar.Plugins.Monitors.Mpris+ other-modules: Xmobar.Plugins.Monitors.Mpris cpp-options: -DMPRIS if flag(with_dbus) || flag(all_extensions)@@ -260,12 +262,12 @@ cpp-options: -DXPM if flag(with_weather) || flag(all_extensions)- exposed-modules: Xmobar.Plugins.Monitors.Weather+ other-modules: Xmobar.Plugins.Monitors.Weather cpp-options: -DWEATHER- build-depends: http-conduit, http-types+ build-depends: http-conduit, http-types, http-client-tls if flag(with_uvmeter)- exposed-modules: Xmobar.Plugins.Monitors.UVMeter+ other-modules: Xmobar.Plugins.Monitors.UVMeter build-depends: http-conduit, http-types cpp-options: -DUVMETER @@ -275,6 +277,7 @@ cpp-options: -DFREEBSD executable xmobar+ default-language: Haskell2010 hs-source-dirs: app main-is: Main.hs build-depends: base,@@ -300,6 +303,7 @@ cpp-options: -DTHREADED_RUNTIME test-suite XmobarTest+ default-language: Haskell2010 type: exitcode-stdio-1.0 hs-source-dirs: src, test main-is: Spec.hs