xmobar 0.39 → 0.40
raw patch · 36 files changed
+1575/−627 lines, 36 files
Files
- changelog.md +10/−1
- doc/plugins.org +184/−137
- doc/quick-start.org +4/−0
- readme.org +16/−15
- src/Xmobar.hs +2/−0
- src/Xmobar/App/EventLoop.hs +1/−0
- src/Xmobar/Plugins/Monitors/Batt.hs +10/−176
- src/Xmobar/Plugins/Monitors/Batt/Common.hs +57/−0
- src/Xmobar/Plugins/Monitors/Batt/FreeBSD.hs +46/−0
- src/Xmobar/Plugins/Monitors/Batt/Linux.hs +130/−0
- src/Xmobar/Plugins/Monitors/Cpu.hs +14/−88
- src/Xmobar/Plugins/Monitors/Cpu/Common.hs +25/−0
- src/Xmobar/Plugins/Monitors/Cpu/FreeBSD.hs +54/−0
- src/Xmobar/Plugins/Monitors/Cpu/Linux.hs +61/−0
- src/Xmobar/Plugins/Monitors/Mem.hs +11/−20
- src/Xmobar/Plugins/Monitors/Mem/FreeBSD.hs +45/−0
- src/Xmobar/Plugins/Monitors/Mem/Linux.hs +33/−0
- src/Xmobar/Plugins/Monitors/Net.hs +14/−72
- src/Xmobar/Plugins/Monitors/Net/Common.hs +50/−0
- src/Xmobar/Plugins/Monitors/Net/FreeBSD.hsc +118/−0
- src/Xmobar/Plugins/Monitors/Net/Linux.hs +69/−0
- src/Xmobar/Plugins/Monitors/Swap.hs +7/−20
- src/Xmobar/Plugins/Monitors/Swap/FreeBSD.hsc +102/−0
- src/Xmobar/Plugins/Monitors/Swap/Linux.hs +35/−0
- src/Xmobar/Plugins/Monitors/Top.hs +26/−83
- src/Xmobar/Plugins/Monitors/Top/Common.hs +32/−0
- src/Xmobar/Plugins/Monitors/Top/FreeBSD.hsc +143/−0
- src/Xmobar/Plugins/Monitors/Top/Linux.hs +92/−0
- src/Xmobar/Plugins/Monitors/Uptime.hs +8/−6
- src/Xmobar/Plugins/Monitors/Uptime/FreeBSD.hsc +52/−0
- src/Xmobar/Plugins/Monitors/Uptime/Linux.hs +24/−0
- src/Xmobar/Plugins/QueueReader.hs +50/−0
- src/Xmobar/X11/Actions.hs +1/−1
- src/Xmobar/X11/Draw.hs +3/−0
- src/Xmobar/X11/Parsers.hs +15/−6
- xmobar.cabal +31/−2
changelog.md view
@@ -1,4 +1,13 @@-## Version 0.39 (unreleased)+## Version 0.40 (November, 2021)++_New features_++ - New plugin: `QueueReader` (Guy Gastineau).+ - Greatly improved FreeBSD support: Mem, Network and Swap monitors+ fixes, and CI build for FreeBSD (Michal Zielonka).+ - New template markup: `<hspace>`(tulthix)++## Version 0.39 (August, 2021) _New features_
doc/plugins.org view
@@ -1,35 +1,37 @@ * System Monitor Plugins -This is the description of the system monitor plugins available in-xmobar. Some of them are only installed when an optional build option is-set: we mention that fact, when needed, in their description.+ This is the description of the system monitor plugins available in+ xmobar. Some of them are only installed when an optional build+ option is set: we mention that fact, when needed, in their+ description. -Each monitor has an =alias= to be used in the output template. Monitors-may have default aliases, see the documentation of the monitor in-question.+ Each monitor has an =alias= to be used in the output+ template. Monitors may have default aliases, see the documentation+ of the monitor in question. -There are two types of arguments: ones that all monitors share (the so-called /default monitor arguments/) and arguments that are specific to a-certain monitor.+ There are two types of arguments: ones that all monitors share (the+ so called /default monitor arguments/) and arguments that are specific+ to a certain monitor. -All Monitors accept a common set of arguments, described below in-[[Default Monitor Arguments]]. Some monitors also accept additional options-that are specific to them. When specifying the list of arguments in your-configuration, the common options come first, followed by =--=, followed-by any monitor-specific options. For example, the following [[=Battery Args RefreshRate=][Battery]]-configuration first sets the global =template= and =Low= arguments and-then specifies the battery-specific =off= option.+ All Monitors accept a common set of arguments, described below in+ [[Default Monitor Arguments]]. Some monitors also accept additional+ options that are specific to them. When specifying the list of+ arguments in your configuration, the common options come first,+ followed by =--=, followed by any monitor-specific options. For+ example, the following [[=Battery Args RefreshRate=][Battery]] configuration first sets the global+ =template= and =Low= arguments and then specifies the battery-specific+ =off= option. -#+begin_src haskell- Run Battery- [ "--template", "<acstatus>"- , "--Low" , "15"- -- battery specific options start here.- , "--"- , "--off" , "<left> (<timeleft>)"- ]- 100-#+end_src+ #+begin_src haskell+ Run Battery+ [ "--template", "<acstatus>"+ , "--Low" , "15"+ -- battery specific options start here.+ , "--"+ , "--off" , "<left> (<timeleft>)"+ ]+ 100+ #+end_src ** Icon Patterns @@ -1144,7 +1146,7 @@ - Default template: =<station>: <tempC>C, rh <rh>% (<hour>)= - Retrieves weather information from http://tgftp.nws.noaa.gov. Here is an [[https://tgftp.nws.noaa.gov/data/observations/metar/decoded/CYLD.TXT][example]], also showcasing the kind of information that may be- extracted.+ extracted. Here is [[https://weather.rap.ucar.edu/surface/stations.txt][a sample list of station IDs]]. *** =WeatherX StationID SkyConditions Args RefreshRate= @@ -1260,8 +1262,8 @@ * Interfacing with Window Managers -Listed below are ways to interface xmobar with your window manager of-choice.+ Listed below are ways to interface xmobar with your window manager+ of choice. ** Property-based Logging *** =XMonadLog=@@ -1436,71 +1438,116 @@ hPutStr writeHandle "Hello World" #+end_src +** Software Transactional Memory++ When invoking xmobar from other Haskell code it can be easier and+ more performant to use shared memory. The following plugins+ leverage =Control.Concurrent.STM= to realize these gains for xmobar.++*** =QueueReader (TQueue a) (a -> String) String=++ - Display data from a Haskell =TQueue a=.++ - This plugin is only useful if you are running xmobar from another+ haskell program like xmonad.++ - You should make an =IO= safe =TQueue a= with =Control.Concurrent.STM.newTQueueIO=.+ Write to it from the user code with =writeTQueue=, and read with =readTQueue=.+ A common use is to overwite =ppOutput= from =XMonad.Hooks.DynamicLog= as shown+ below.++ #+begin_src haskell+ main :: IO ()+ main = do+ q <- STM.newTQueueIO @String+ bar <- forkIO $ xmobar myConf+ { commands = Run (QueueReader q id "XMonadLog") : commands myConf }+ xmonad $ def { logHook = logWorkspacesToQueue q }++ logWorkspacesToQueue :: STM.TQueue String -> X ()+ logWorkspacesToQueue q =+ dynamicLogWithPP def { ppOutput = STM.atomically . STM.writeTQueue q }+ where+ -- Manage the PrettyPrinting configuration here.+ ppLayout' :: String -> String+ ppLayout' "Spacing Tall" = xpm "layout-spacing-tall"+ ppLayout' "Spacing Mirror Tall" = xpm "layout-spacing-mirror"+ ppLayout' "Spacing Full" = xpm "layout-full"+ ppLayout' x = x++ icon :: String -> String+ icon path = "<icon=" ++ path ++ "/>"++ xpm :: String -> String+ xpm = icon . (++ ".xpm")+ #+end_src+ * Executing External Commands -In order to execute an external command you can either write the command-name in the template, in this case it will be executed without-arguments, or you can configure it in the "commands" configuration-option list with the Com template command:+ In order to execute an external command you can either write the+ command name in the template, in this case it will be executed+ without arguments, or you can configure it in the "commands"+ configuration option list with the Com template command: -=Com ProgramName Args Alias RefreshRate=+ =Com ProgramName Args Alias RefreshRate= -- ProgramName: the name of the program-- Args: the arguments to be passed to the program at execution time-- RefreshRate: number of tenths of second between re-runs of the- command. A zero or negative rate means that the command will be- executed only once.-- Alias: a name to be used in the template. If the alias is en empty- string the program name can be used in the template.+ - ProgramName: the name of the program+ - Args: the arguments to be passed to the program at execution time+ - RefreshRate: number of tenths of second between re-runs of the+ command. A zero or negative rate means that the command will be+ executed only once.+ - Alias: a name to be used in the template. If the alias is en empty+ string the program name can be used in the template. -E.g.:+ E.g.: -#+begin_src haskell- Run Com "uname" ["-s","-r"] "" 0-#+end_src+ #+begin_src haskell+ Run Com "uname" ["-s","-r"] "" 0+ #+end_src -can be used in the output template as =%uname%= (and xmobar will call-/uname/ only once), while+ can be used in the output template as =%uname%= (and xmobar will call+ /uname/ only once), while -#+begin_src haskell- Run Com "date" ["+\"%a %b %_d %H:%M\""] "mydate" 600-#+end_src+ #+begin_src haskell+ Run Com "date" ["+\"%a %b %_d %H:%M\""] "mydate" 600+ #+end_src -can be used in the output template as =%mydate%=.+ can be used in the output template as =%mydate%=. -Sometimes, you don't mind if the command executed exits with an error,-or you might want to display a custom message in that case. To that end,-you can use the =ComX= variant:+ Sometimes, you don't mind if the command executed exits with an+ error, or you might want to display a custom message in that+ case. To that end, you can use the =ComX= variant: -=ComX ProgramName Args ExitMessage Alias RefreshRate=+ =ComX ProgramName Args ExitMessage Alias RefreshRate= -Works like =Com=, but displaying =ExitMessage= (a string) if the-execution fails. For instance:+ Works like =Com=, but displaying =ExitMessage= (a string) if the+ execution fails. For instance: -#+begin_src haskell- Run ComX "date" ["+\"%a %b %_d %H:%M\""] "N/A" "mydate" 600-#+end_src+ #+begin_src haskell+ Run ComX "date" ["+\"%a %b %_d %H:%M\""] "N/A" "mydate" 600+ #+end_src -will display "N/A" if for some reason the =date= invocation fails.+ will display "N/A" if for some reason the =date= invocation fails. * The DBus Interface -When compiled with the optional =with_dbus= flag, xmobar can be-controlled over dbus. All signals defined in [[https://github.com/jaor/xmobar/blob/master/src/Xmobar/System/Signal.hs][src/Signal.hs]] as =data-SignalType= can now be sent over dbus to xmobar. Due to current-limitations of the implementation only one process of xmobar can acquire-the dbus. This is handled on a first-come-first-served basis, meaning-that the first process will get the dbus interface. Other processes will-run without further problems, yet have no dbus interface.+ When compiled with the optional =with_dbus= flag, xmobar can be+ controlled over dbus. All signals defined in [[https://github.com/jaor/xmobar/blob/master/src/Xmobar/System/Signal.hs][src/Signal.hs]] as =data+ SignalType= can now be sent over dbus to xmobar. Due to current+ limitations of the implementation only one process of xmobar can+ acquire the dbus. This is handled on a first-come-first-served+ basis, meaning that the first process will get the dbus+ interface. Other processes will run without further problems, yet+ have no dbus interface. -- Bus Name: =org.Xmobar.Control=-- Object Path: =/org/Xmobar/Control=-- Member Name: Any of SignalType, e.g. =string:Reveal=-- Interface Name: =org.Xmobar.Control=+ - Bus Name: =org.Xmobar.Control=+ - Object Path: =/org/Xmobar/Control=+ - Member Name: Any of SignalType, e.g. =string:Reveal=+ - Interface Name: =org.Xmobar.Control= -An example using the =dbus-send= command line utility:+ An example using the =dbus-send= command line utility: -#+begin_src shell+ #+begin_src shell dbus-send \ --session \ --dest=org.Xmobar.Control \@@ -1509,82 +1556,82 @@ '/org/Xmobar/Control' \ org.Xmobar.Control.SendSignal \ "string:Toggle 0"-#+end_src+ #+end_src -It is also possible to send multiple signals at once:+ It is also possible to send multiple signals at once: -#+begin_src shell- # send to another screen, reveal and toggle the persistent flag- dbus-send [..] \- "string:ChangeScreen 0" "string:Reveal 0" "string:TogglePersistent"-#+end_src+ #+begin_src shell+ # send to another screen, reveal and toggle the persistent flag+ dbus-send [..] \+ "string:ChangeScreen 0" "string:Reveal 0" "string:TogglePersistent"+ #+end_src -The =Toggle=, =Reveal=, and =Hide= signals take an additional integer-argument that denotes an initial delay, in tenths of a second, before-the command takes effect.+ The =Toggle=, =Reveal=, and =Hide= signals take an additional integer+ argument that denotes an initial delay, in tenths of a second,+ before the command takes effect. ** Example for using the DBus IPC interface with XMonad -Bind the key which should {,un}map xmobar to a dummy value. This is-necessary for {,un}grabKey in xmonad.+ Bind the key which should {,un}map xmobar to a dummy value. This is+ necessary for {,un}grabKey in xmonad. -#+begin_src haskell- ((0, xK_Alt_L), pure ())-#+end_src+ #+begin_src haskell+ ((0, xK_Alt_L), pure ())+ #+end_src -Also, install =avoidStruts= layout modifier from-=XMonad.Hooks.ManageDocks=+ Also, install =avoidStruts= layout modifier from+ =XMonad.Hooks.ManageDocks= -Finally, install these two event hooks (=handleEventHook= in =XConfig=)-=myDocksEventHook= is a replacement for =docksEventHook= which reacts on-unmap events as well (which =docksEventHook= doesn't).+ Finally, install these two event hooks (=handleEventHook= in =XConfig=)+ =myDocksEventHook= is a replacement for =docksEventHook= which reacts+ on unmap events as well (which =docksEventHook= doesn't). -#+begin_src haskell- import qualified XMonad.Util.ExtensibleState as XS+ #+begin_src haskell+ import qualified XMonad.Util.ExtensibleState as XS - data DockToggleTime = DTT { lastTime :: Time } deriving (Eq, Show, Typeable)+ data DockToggleTime = DTT { lastTime :: Time } deriving (Eq, Show, Typeable) - instance ExtensionClass DockToggleTime where- initialValue = DTT 0+ instance ExtensionClass DockToggleTime where+ initialValue = DTT 0 - toggleDocksHook :: Int -> KeySym -> Event -> X All- toggleDocksHook to ks ( KeyEvent { ev_event_display = d- , ev_event_type = et- , ev_keycode = ekc- , ev_time = etime- } ) =- io (keysymToKeycode d ks) >>= toggleDocks >> return (All True)- where- toggleDocks kc- | ekc == kc && et == keyPress = do- safeSendSignal ["Reveal 0", "TogglePersistent"]- XS.put ( DTT etime )- | ekc == kc && et == keyRelease = do- gap <- XS.gets ( (-) etime . lastTime )- safeSendSignal [ "TogglePersistent"- , "Hide " ++ show (if gap < 400 then to else 0)- ]- | otherwise = return ()+ toggleDocksHook :: Int -> KeySym -> Event -> X All+ toggleDocksHook to ks ( KeyEvent { ev_event_display = d+ , ev_event_type = et+ , ev_keycode = ekc+ , ev_time = etime+ } ) =+ io (keysymToKeycode d ks) >>= toggleDocks >> return (All True)+ where+ toggleDocks kc+ | ekc == kc && et == keyPress = do+ safeSendSignal ["Reveal 0", "TogglePersistent"]+ XS.put ( DTT etime )+ | ekc == kc && et == keyRelease = do+ gap <- XS.gets ( (-) etime . lastTime )+ safeSendSignal [ "TogglePersistent"+ , "Hide " ++ show (if gap < 400 then to else 0)+ ]+ | otherwise = return () - safeSendSignal s = catchX (io $ sendSignal s) (return ())- sendSignal = withSession . callSignal- withSession mc = connectSession >>= \c -> callNoReply c mc >> disconnect c- callSignal :: [String] -> MethodCall- callSignal s = ( methodCall- ( objectPath_ "/org/Xmobar/Control" )- ( interfaceName_ "org.Xmobar.Control" )- ( memberName_ "SendSignal" )- ) { methodCallDestination = Just $ busName_ "org.Xmobar.Control"- , methodCallBody = map toVariant s- }+ safeSendSignal s = catchX (io $ sendSignal s) (return ())+ sendSignal = withSession . callSignal+ withSession mc = connectSession >>= \c -> callNoReply c mc >> disconnect c+ callSignal :: [String] -> MethodCall+ callSignal s = ( methodCall+ ( objectPath_ "/org/Xmobar/Control" )+ ( interfaceName_ "org.Xmobar.Control" )+ ( memberName_ "SendSignal" )+ ) { methodCallDestination = Just $ busName_ "org.Xmobar.Control"+ , methodCallBody = map toVariant s+ } - toggleDocksHook _ _ _ = return (All True)+ toggleDocksHook _ _ _ = return (All True) - myDocksEventHook :: Event -> X All- myDocksEventHook e = do- when (et == mapNotify || et == unmapNotify) $- whenX ((not `fmap` (isClient w)) <&&> runQuery checkDock w) refresh- return (All True)- where w = ev_window e- et = ev_event_type e-#+end_src+ myDocksEventHook :: Event -> X All+ myDocksEventHook e = do+ when (et == mapNotify || et == unmapNotify) $+ whenX ((not `fmap` (isClient w)) <&&> runQuery checkDock w) refresh+ return (All True)+ where w = ev_window e+ et = ev_event_type e+ #+end_src
doc/quick-start.org view
@@ -215,6 +215,10 @@ - =<fn=1>string</fn>= will print =string= with the first font from =additionalFonts=. The index =0= corresponds to the standard font. +- =<hspace=X/>= will insert a blank horizontal space of =X= pixels.+ For example, to add a blank horizontal space of 123 pixels,+ =<hspace=123/>= may be used.+ - =<icon=/path/to/icon.xbm/>= will insert the given bitmap. XPM image format is also supported when compiled with the =with_xpm= flag.
readme.org view
@@ -129,21 +129,22 @@ In particular, xmobar incorporates patches by Mohammed Alshiekh, Alex Ameen, Axel Angel, Dhananjay Balan, Claudio Bley, Dragos Boca, Ben Boeckel, Ivan Brennan, 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, Sam Kirby, Lennart Kolmodin, Krzysztof Kosciuszkiewicz,-Dmitry Kurochkin, Todd Lunter, Vanessa McHale, Robert J. Macomber,-Dmitry Malikov, David McLean, Joan MIlev, Marcin Mikołajczyk, Dino-Morelli, Tony Morris, Eric Mrak, Thiago Negri, Edward O'Callaghan,-Svein Ove, Martin Perner, Jens Petersen, Alexander Polakov, Sibi-Prabakaran, Pavan Rikhi, Petr Rockai, Andrew Emmanuel Rosa,-Sackville-West, Amir Saeid, 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, Nikolay Yakimov,-aEdward Z. Yang, Leo Zhang, and Norbert Zeh.+Antoine Eiche, Nathaniel Wesley Filardo, Guy Gastineau, John Goerzen,+Reto Hablützel, Juraj Hercek, Tomáš Janoušek, Ada Joule, Spencer+Janssen, Roman Joost, Jochen Keil, Sam Kirby, Lennart Kolmodin,+Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Todd Lunter, Vanessa+McHale, Robert J. Macomber, Dmitry Malikov, David McLean, Joan MIlev,+Marcin Mikołajczyk, Dino Morelli, Tony Morris, Eric Mrak, Thiago+Negri, Edward O'Callaghan, Svein Ove, Martin Perner, Jens Petersen,+Alexander Polakov, Sibi Prabakaran, Pavan Rikhi, Petr Rockai, Andrew+Emmanuel Rosa, Sackville-West, Amir Saeid, 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, Nikolay Yakimov, Edward Z. Yang, Leo Zhang, Norbert Zeh, and+Michal Zielonka. ** Thanks
src/Xmobar.hs view
@@ -33,6 +33,7 @@ #endif , module Xmobar.Plugins.EWMH , module Xmobar.Plugins.HandleReader+ , module Xmobar.Plugins.QueueReader , module Xmobar.Plugins.Kbd , module Xmobar.Plugins.Locks #ifdef INOTIFY@@ -60,6 +61,7 @@ #endif import Xmobar.Plugins.EWMH import Xmobar.Plugins.HandleReader+import Xmobar.Plugins.QueueReader import Xmobar.Plugins.Kbd import Xmobar.Plugins.Locks #ifdef INOTIFY
src/Xmobar/App/EventLoop.hs view
@@ -265,6 +265,7 @@ iconW i = maybe 0 Bitmap.width (lookup i $ iconS conf) 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)+ getCoords (Hspace w,_,_,a) = return (a, 0, fi w) partCoord off xs = map (\(a, x, x') -> (fromJust a, x, x')) $ filter (\(a, _,_) -> isJust a) $ scanl (\(_,_,x') (a,_,w') -> (a, x', x' + w'))
src/Xmobar/Plugins/Monitors/Batt.hs view
@@ -17,45 +17,19 @@ module Xmobar.Plugins.Monitors.Batt ( battConfig, runBatt, runBatt' ) where -import System.Process (system)-import Control.Monad (void, unless)+import Xmobar.Plugins.Monitors.Batt.Common (BattOpts(..)+ , Result(..)+ , Status(..)) 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)-import Data.Ord (comparing)-import Text.Read (readMaybe) -data BattOpts = BattOpts- { onString :: String- , offString :: String- , idleString :: String- , posColor :: Maybe String- , lowWColor :: Maybe String- , mediumWColor :: Maybe String- , highWColor :: Maybe String- , lowThreshold :: Float- , highThreshold :: Float- , onLowAction :: Maybe String- , actionThreshold :: Float- , onlineFile :: FilePath- , scale :: Float- , onIconPattern :: Maybe IconPattern- , offIconPattern :: Maybe IconPattern- , idleIconPattern :: Maybe IconPattern- , lowString :: String- , mediumString :: String- , highString :: String- , incPerc :: Bool- }+#if defined(freebsd_HOST_OS)+import qualified Xmobar.Plugins.Monitors.Batt.FreeBSD as MB+#else+import qualified Xmobar.Plugins.Monitors.Batt.Linux as MB+#endif + defaultOpts :: BattOpts defaultOpts = BattOpts { onString = "On"@@ -108,34 +82,11 @@ , Option "" ["highs"] (ReqArg (\x o -> o { highString = x }) "") "" ] -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-sysDir = "/sys/class/power_supply"- battConfig :: IO MConfig battConfig = mkMConfig "Batt: <watts>, <left>% / <timeleft>" -- template ["leftbar", "leftvbar", "left", "acstatus", "timeleft", "watts", "leftipat"] -- replacements -data Files = Files- { fFull :: String- , fNow :: String- , fVoltage :: String- , fCurrent :: String- , fStatus :: String- , isCurrent :: Bool- } | NoFiles deriving Eq--data Battery = Battery- { full :: !Float- , now :: !Float- , power :: !Float- , status :: !String- }- data BatteryStatus = BattHigh | BattMedium@@ -153,130 +104,13 @@ 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--batteryFiles :: String -> IO Files-batteryFiles bat =- do is_charge <- exists "charge_now"- is_energy <- if is_charge then return False else exists "energy_now"- is_power <- exists "power_now"- plain <- exists (if is_charge then "charge_full" else "energy_full")- let cf = if is_power then "power_now" else "current_now"- sf = if plain then "" else "_design"- return $ case (is_charge, is_energy) of- (True, _) -> files "charge" cf sf is_power- (_, True) -> files "energy" cf sf is_power- _ -> NoFiles- where prefix = sysDir </> bat- exists = safeFileExist prefix- files ch cf sf ip = Files { fFull = prefix </> ch ++ "_full" ++ sf- , fNow = prefix </> ch ++ "_now"- , fCurrent = prefix </> cf- , fVoltage = prefix </> "voltage_now"- , fStatus = prefix </> "status"- , isCurrent = not ip}--haveAc :: FilePath -> IO Bool-haveAc f =- handle onError $ withFile (sysDir </> f) ReadMode (fmap (== "1") . hGetLine)- where onError = const (return False) :: SomeException -> IO Bool--readBattery :: Float -> Files -> IO Battery-readBattery _ NoFiles = return $ Battery 0 0 0 "Unknown"-readBattery sc files =- do a <- grab $ fFull files- b <- grab $ fNow files- d <- grab $ fCurrent files- s <- grabs $ fStatus files- let sc' = if isCurrent files then sc / 10 else sc- a' = max a b -- sometimes the reported max charge is lower than- return $ Battery (3600 * a' / sc') -- wattseconds- (3600 * b / sc') -- wattseconds- (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- grabs f = handle onError' $ withFile f ReadMode hGetLine- onError' = const (return "Unknown") :: SomeException -> IO String---- sortOn is only available starting at ghc 7.10-sortOn :: Ord b => (a -> b) -> [a] -> [a]-sortOn f =- map snd . sortBy (comparing fst) . map (\x -> let y = f x in y `seq` (y, x))--mostCommonDef :: Eq a => a -> [a] -> a-mostCommonDef x xs = head $ last $ [x] : sortOn length (group xs)--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)- let sign = if ac then 1 else -1- ft = sum (map full bats)- left = if ft > 0 then sum (map now bats) / ft else 0- watts = sign * sum (map power bats)- time = if watts == 0 then 0 else max 0 (sum $ map time' bats)- mwatts = if watts == 0 then 1 else sign * watts- time' b = (if ac then full b - now b else now b) / mwatts- statuses :: [Status]- statuses = map (fromMaybe Unknown . readMaybe)- (sort (map status bats))- acst = mostCommonDef Unknown $ filter (Unknown/=) statuses- racst | acst /= Unknown = acst- | time == 0 = Idle- | ac = Charging- | 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 $ parseOptsWith options defaultOpts args-#ifdef FREEBSD- c <- io $ readBatteriesFbsd opts-#else- c <- io $ readBatteriesLinux opts =<< mapM batteryFiles bfs-#endif+ c <- io $ MB.readBatteries opts bfs formatResult c opts formatResult :: Result -> BattOpts -> Monitor String
+ src/Xmobar/Plugins/Monitors/Batt/Common.hs view
@@ -0,0 +1,57 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Batt.Common+-- Copyright : (c) 2010, 2011, 2012, 2013, 2015, 2016, 2018, 2019 Jose A Ortega+-- (c) 2010 Andrea Rossato, Petr Rockai+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A battery monitor for Xmobar+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Batt.Common (BattOpts(..)+ , Result(..)+ , Status(..)+ , maybeAlert) where++import System.Process (system)+import Control.Monad (unless, void)+import Xmobar.Plugins.Monitors.Common++data Status = Charging | Discharging | Full | Idle | Unknown deriving (Read, Eq)+-- Result perc watts time-seconds Status+data Result = Result Float Float Float Status | NA++data BattOpts = BattOpts+ { onString :: String+ , offString :: String+ , idleString :: String+ , posColor :: Maybe String+ , lowWColor :: Maybe String+ , mediumWColor :: Maybe String+ , highWColor :: Maybe String+ , lowThreshold :: Float+ , highThreshold :: Float+ , onLowAction :: Maybe String+ , actionThreshold :: Float+ , onlineFile :: FilePath+ , scale :: Float+ , onIconPattern :: Maybe IconPattern+ , offIconPattern :: Maybe IconPattern+ , idleIconPattern :: Maybe IconPattern+ , lowString :: String+ , mediumString :: String+ , highString :: String+ , incPerc :: Bool+ }++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
+ src/Xmobar/Plugins/Monitors/Batt/FreeBSD.hs view
@@ -0,0 +1,46 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Batt.FreeBSD+-- Copyright : (c) 2010, 2011, 2012, 2013, 2015, 2016, 2018, 2019 Jose A Ortega+-- (c) 2010 Andrea Rossato, Petr Rockai+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A battery monitor for Xmobar+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Batt.FreeBSD (readBatteries) where++import Xmobar.Plugins.Monitors.Batt.Common (BattOpts(..)+ , Result(..)+ , Status(..)+ , maybeAlert)++import Control.Monad (unless)+import System.BSD.Sysctl (sysctlReadInt)++battStatus :: Int -> Status+battStatus x+ | x == 1 = Discharging+ | x == 2 = Charging+ | otherwise = Unknown++readBatteries :: BattOpts -> [String] -> IO Result+readBatteries 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 battStatus $ fromIntegral st+ unless ac (maybeAlert opts p)+ return (Result p w t sts)
+ src/Xmobar/Plugins/Monitors/Batt/Linux.hs view
@@ -0,0 +1,130 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Batt.Linux+-- Copyright : (c) 2010, 2011, 2012, 2013, 2015, 2016, 2018, 2019 Jose A Ortega+-- (c) 2010 Andrea Rossato, Petr Rockai+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A battery monitor for Xmobar+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Batt.Linux (readBatteries) where++import Xmobar.Plugins.Monitors.Batt.Common (BattOpts(..)+ , Result(..)+ , Status(..)+ , maybeAlert)++import Control.Monad (unless)+import Control.Exception (SomeException, handle)+import System.FilePath ((</>))+import System.IO (IOMode(ReadMode), hGetLine, withFile)+import System.Posix.Files (fileExist)+import Data.List (sort, sortBy, group)+import Data.Maybe (fromMaybe)+import Data.Ord (comparing)+import Text.Read (readMaybe)++data Files = Files+ { fFull :: String+ , fNow :: String+ , fVoltage :: String+ , fCurrent :: String+ , fStatus :: String+ , isCurrent :: Bool+ } | NoFiles deriving Eq++data Battery = Battery+ { full :: !Float+ , now :: !Float+ , power :: !Float+ , status :: !String+ }++sysDir :: FilePath+sysDir = "/sys/class/power_supply"++safeFileExist :: String -> String -> IO Bool+safeFileExist d f = handle noErrors $ fileExist (d </> f)+ where noErrors = const (return False) :: SomeException -> IO Bool++batteryFiles :: String -> IO Files+batteryFiles bat =+ do is_charge <- exists "charge_now"+ is_energy <- if is_charge then return False else exists "energy_now"+ is_power <- exists "power_now"+ plain <- exists (if is_charge then "charge_full" else "energy_full")+ let cf = if is_power then "power_now" else "current_now"+ sf = if plain then "" else "_design"+ return $ case (is_charge, is_energy) of+ (True, _) -> files "charge" cf sf is_power+ (_, True) -> files "energy" cf sf is_power+ _ -> NoFiles+ where prefix = sysDir </> bat+ exists = safeFileExist prefix+ files ch cf sf ip = Files { fFull = prefix </> ch ++ "_full" ++ sf+ , fNow = prefix </> ch ++ "_now"+ , fCurrent = prefix </> cf+ , fVoltage = prefix </> "voltage_now"+ , fStatus = prefix </> "status"+ , isCurrent = not ip}++haveAc :: FilePath -> IO Bool+haveAc f =+ handle onError $ withFile (sysDir </> f) ReadMode (fmap (== "1") . hGetLine)+ where onError = const (return False) :: SomeException -> IO Bool++readBattery :: Float -> Files -> IO Battery+readBattery _ NoFiles = return $ Battery 0 0 0 "Unknown"+readBattery sc files =+ do a <- grab $ fFull files+ b <- grab $ fNow files+ d <- grab $ fCurrent files+ s <- grabs $ fStatus files+ let sc' = if isCurrent files then sc / 10 else sc+ a' = max a b -- sometimes the reported max charge is lower than+ return $ Battery (3600 * a' / sc') -- wattseconds+ (3600 * b / sc') -- wattseconds+ (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+ grabs f = handle onError' $ withFile f ReadMode hGetLine+ onError' = const (return "Unknown") :: SomeException -> IO String++-- sortOn is only available starting at ghc 7.10+sortOn :: Ord b => (a -> b) -> [a] -> [a]+sortOn f =+ map snd . sortBy (comparing fst) . map (\x -> let y = f x in y `seq` (y, x))++mostCommonDef :: Eq a => a -> [a] -> a+mostCommonDef x xs = head $ last $ [x] : sortOn length (group xs)++readBatteries :: BattOpts -> [String] -> IO Result+readBatteries opts bfs =+ do bfs' <- mapM batteryFiles bfs+ let bfs'' = filter (/= NoFiles) bfs'+ bats <- mapM (readBattery (scale opts)) (take 3 bfs'')+ ac <- haveAc (onlineFile opts)+ let sign = if ac then 1 else -1+ ft = sum (map full bats)+ left = if ft > 0 then sum (map now bats) / ft else 0+ watts = sign * sum (map power bats)+ time = if watts == 0 then 0 else max 0 (sum $ map time' bats)+ mwatts = if watts == 0 then 1 else sign * watts+ time' b = (if ac then full b - now b else now b) / mwatts+ statuses :: [Status]+ statuses = map (fromMaybe Unknown . readMaybe)+ (sort (map status bats))+ acst = mostCommonDef Unknown $ filter (Unknown/=) statuses+ racst | acst /= Unknown = acst+ | time == 0 = Idle+ | ac = Charging+ | otherwise = Discharging+ unless ac (maybeAlert opts left)+ return $ if isNaN left then NA else Result left watts time racst
src/Xmobar/Plugins/Monitors/Cpu.hs view
@@ -20,23 +20,26 @@ ( startCpu , runCpu , cpuConfig- , CpuDataRef+ , MC.CpuDataRef , CpuOpts , CpuArguments- , parseCpu+ , MC.parseCpu , getArguments ) where import Xmobar.Plugins.Monitors.Common-import qualified Data.ByteString.Lazy.Char8 as B-import Data.IORef (IORef, newIORef, readIORef, writeIORef)-#ifdef FREEBSD-import System.BSD.Sysctl (sysctlPeekArray)-#endif+import Data.IORef (newIORef) import System.Console.GetOpt import Xmobar.App.Timer (doEveryTenthSeconds) import Control.Monad (void)+import Xmobar.Plugins.Monitors.Cpu.Common (CpuData(..)) +#if defined(freebsd_HOST_OS)+import qualified Xmobar.Plugins.Monitors.Cpu.FreeBSD as MC+#else+import qualified Xmobar.Plugins.Monitors.Cpu.Linux as MC+#endif+ newtype CpuOpts = CpuOpts { loadIconPattern :: Maybe IconPattern }@@ -94,83 +97,6 @@ , iowaitField ] -data CpuData = CpuData {- cpuUser :: !Float,- cpuNice :: !Float,- cpuSystem :: !Float,- cpuIdle :: !Float,- cpuIowait :: !Float,- cpuTotal :: !Float- }--#ifdef FREEBSD--- kern.cp_time data from the previous iteration for computing the difference-type CpuDataRef = IORef [Word]--cpuData :: IO [Word]-cpuData = sysctlPeekArray "kern.cp_time" :: IO [Word]--parseCpu :: CpuDataRef -> IO CpuData-parseCpu cref = do- prev <- readIORef cref- curr <- cpuData- writeIORef cref curr- let diff = map fromIntegral $ zipWith (-) curr prev- user = diff !! 0- nice = diff !! 1- system = diff !! 2- intr = diff !! 3- idle = diff !! 4- total = user + nice + system + intr + idle- return CpuData- { cpuUser = user/total- , cpuNice = nice/total- , cpuSystem = (system+intr)/total- , cpuIdle = idle/total- , cpuIowait = 0- , cpuTotal = user/total- }-#else-type CpuDataRef = IORef [Int]---- Details about the fields here: https://www.kernel.org/doc/Documentation/filesystems/proc.txt-cpuData :: IO [Int]-cpuData = cpuParser <$> B.readFile "/proc/stat"--readInt :: B.ByteString -> Int-readInt bs = case B.readInt bs of- Nothing -> 0- Just (i, _) -> i--cpuParser :: B.ByteString -> [Int]-cpuParser = map readInt . tail . B.words . head . B.lines--convertToCpuData :: [Float] -> CpuData-convertToCpuData (u:n:s:ie:iw:_) =- CpuData- { cpuUser = u- , cpuNice = n- , cpuSystem = s- , cpuIdle = ie- , cpuIowait = iw- , cpuTotal = sum [u, n, s]- }-convertToCpuData args = error $ "convertToCpuData: Unexpected list" <> show args--parseCpu :: CpuDataRef -> IO CpuData-parseCpu cref =- do a <- readIORef cref- b <- cpuData- writeIORef cref b- let dif = zipWith (-) b a- tot = fromIntegral $ sum dif- safeDiv n = case tot of- 0 -> 0- v -> fromIntegral n / v- percent = map safeDiv dif- return $ convertToCpuData percent-#endif- data Field = Field { fieldName :: !String, fieldCompute :: !ShouldCompute@@ -235,7 +161,7 @@ data CpuArguments = CpuArguments- { cpuDataRef :: !CpuDataRef+ { cpuDataRef :: !MC.CpuDataRef , cpuParams :: !MonitorConfig , cpuArgs :: ![String] , cpuOpts :: !CpuOpts@@ -247,9 +173,9 @@ getArguments :: [String] -> IO CpuArguments getArguments cpuArgs = do- initCpuData <- cpuData+ initCpuData <- MC.cpuData cpuDataRef <- newIORef initCpuData- void $ parseCpu cpuDataRef+ void $ MC.parseCpu cpuDataRef cpuParams <- computeMonitorConfig cpuArgs cpuConfig cpuInputTemplate <- runTemplateParser cpuParams cpuAllTemplate <- runExportParser (pExport cpuParams)@@ -270,7 +196,7 @@ runCpu :: CpuArguments -> IO String runCpu args@CpuArguments {..} = do- cpuValue <- parseCpu cpuDataRef+ cpuValue <- MC.parseCpu cpuDataRef temMonitorValues <- formatCpu args cpuValue let templateInput = TemplateInput
+ src/Xmobar/Plugins/Monitors/Cpu/Common.hs view
@@ -0,0 +1,25 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Cpu.Common+-- Copyright : (c) 2011, 2017 Jose Antonio Ortega Ruiz+-- (c) 2007-2010 Andrea Rossato+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A cpu monitor for Xmobar+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Cpu.Common (CpuData(..)) where++data CpuData = CpuData {+ cpuUser :: !Float,+ cpuNice :: !Float,+ cpuSystem :: !Float,+ cpuIdle :: !Float,+ cpuIowait :: !Float,+ cpuTotal :: !Float+ }
+ src/Xmobar/Plugins/Monitors/Cpu/FreeBSD.hs view
@@ -0,0 +1,54 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Cpu.FreeBSD+-- Copyright : (c) 2011, 2017 Jose Antonio Ortega Ruiz+-- (c) 2007-2010 Andrea Rossato+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A cpu monitor for Xmobar+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Cpu.FreeBSD (parseCpu+ , CpuDataRef+ , cpuData) where++import Xmobar.Plugins.Monitors.Cpu.Common (CpuData(..))+import Data.IORef (IORef, readIORef, writeIORef)+import System.BSD.Sysctl (sysctlPeekArray)++-- kern.cp_time data from the previous iteration for computing the difference+type CpuDataRef = IORef [Word]++cpuData :: IO [Word]+cpuData = sysctlPeekArray "kern.cp_time" :: IO [Word]++parseCpu :: CpuDataRef -> IO CpuData+parseCpu cref = do+ prev <- readIORef cref+ curr <- cpuData+ writeIORef cref curr+ let diff = map fromIntegral $ zipWith (-) curr prev+ user = head diff+ nice = diff !! 1+ system = diff !! 2+ intr = diff !! 3+ idle = diff !! 4+ total = user + nice + system + intr + idle+ cpuUserPerc = if total > 0 then user/total else 0+ cpuNicePerc = if total > 0 then nice/total else 0+ cpuSystemPerc = if total > 0 then (system+intr)/total else 0+ cpuIdlePerc = if total > 0 then idle/total else 0++ return CpuData+ { cpuUser = cpuUserPerc+ , cpuNice = cpuNicePerc+ , cpuSystem = cpuSystemPerc+ , cpuIdle = cpuIdlePerc+ , cpuIowait = 0+ , cpuTotal = cpuUserPerc+cpuSystemPerc+ }
+ src/Xmobar/Plugins/Monitors/Cpu/Linux.hs view
@@ -0,0 +1,61 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Cpu.Linux+-- Copyright : (c) 2011, 2017 Jose Antonio Ortega Ruiz+-- (c) 2007-2010 Andrea Rossato+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A cpu monitor for Xmobar+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Cpu.Linux (parseCpu+ , CpuDataRef+ , cpuData) where++import Xmobar.Plugins.Monitors.Cpu.Common (CpuData(..))+import qualified Data.ByteString.Lazy.Char8 as B+import Data.IORef (IORef, readIORef, writeIORef)++type CpuDataRef = IORef [Int]++-- Details about the fields here: https://www.kernel.org/doc/Documentation/filesystems/proc.txt+cpuData :: IO [Int]+cpuData = cpuParser <$> B.readFile "/proc/stat"++readInt :: B.ByteString -> Int+readInt bs = case B.readInt bs of+ Nothing -> 0+ Just (i, _) -> i++cpuParser :: B.ByteString -> [Int]+cpuParser = map readInt . tail . B.words . head . B.lines++convertToCpuData :: [Float] -> CpuData+convertToCpuData (u:n:s:ie:iw:_) =+ CpuData+ { cpuUser = u+ , cpuNice = n+ , cpuSystem = s+ , cpuIdle = ie+ , cpuIowait = iw+ , cpuTotal = sum [u, n, s]+ }+convertToCpuData args = error $ "convertToCpuData: Unexpected list" <> show args++parseCpu :: CpuDataRef -> IO CpuData+parseCpu cref =+ do a <- readIORef cref+ b <- cpuData+ writeIORef cref b+ let dif = zipWith (-) b a+ tot = fromIntegral $ sum dif+ safeDiv n = case tot of+ 0 -> 0+ v -> fromIntegral n / v+ percent = map safeDiv dif+ return $ convertToCpuData percent
src/Xmobar/Plugins/Monitors/Mem.hs view
@@ -1,3 +1,4 @@+{-#LANGUAGE CPP #-} ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Mem@@ -15,9 +16,15 @@ module Xmobar.Plugins.Monitors.Mem (memConfig, runMem, totalMem, usedMem) where import Xmobar.Plugins.Monitors.Common-import qualified Data.Map as M import System.Console.GetOpt +#if defined(freebsd_HOST_OS)+import qualified Xmobar.Plugins.Monitors.Mem.FreeBSD as MM+#else+import qualified Xmobar.Plugins.Monitors.Mem.Linux as MM+#endif++ data MemOpts = MemOpts { usedIconPattern :: Maybe IconPattern , freeIconPattern :: Maybe IconPattern@@ -49,27 +56,11 @@ "usedratio", "freeratio", "availableratio", "total", "free", "buffer", "cache", "available", "used"] -- available replacements -fileMEM :: IO String-fileMEM = readFile "/proc/meminfo"--parseMEM :: IO [Float]-parseMEM =- do file <- fileMEM- let content = map words $ take 8 $ lines file- info = M.fromList $ map (\line -> (head line, (read $ line !! 1 :: Float) / 1024)) content- [total, free, buffer, cache] = map (info M.!) ["MemTotal:", "MemFree:", "Buffers:", "Cached:"]- available = M.findWithDefault (free + buffer + cache) "MemAvailable:" info- used = total - available- usedratio = used / total- freeratio = free / total- availableratio = available / total- return [usedratio, freeratio, availableratio, total, free, buffer, cache, available, used]- totalMem :: IO Float-totalMem = fmap ((*1024) . (!!1)) parseMEM+totalMem = fmap ((*1024) . (!!1)) MM.parseMEM usedMem :: IO Float-usedMem = fmap ((*1024) . (!!6)) parseMEM+usedMem = fmap ((*1024) . (!!6)) MM.parseMEM formatMem :: MemOpts -> [Float] -> Monitor [String] formatMem opts (r:fr:ar:xs) =@@ -84,7 +75,7 @@ runMem :: [String] -> Monitor String runMem argv =- do m <- io parseMEM+ do m <- io MM.parseMEM opts <- io $ parseOptsWith options defaultOpts argv l <- formatMem opts m parseTemplate l
+ src/Xmobar/Plugins/Monitors/Mem/FreeBSD.hs view
@@ -0,0 +1,45 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Mem.FreeBSD+-- Copyright : (c) Andrea Rossato+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A memory monitor for Xmobar+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Mem.FreeBSD (parseMEM) where++import System.BSD.Sysctl (sysctlReadUInt)++parseMEM :: IO [Float]+parseMEM = do stats <- mapM sysctlReadUInt [+ "vm.stats.vm.v_page_size"+ , "vm.stats.vm.v_page_count"+ , "vm.stats.vm.v_free_count"+ , "vm.stats.vm.v_active_count"+ , "vm.stats.vm.v_inactive_count"+ , "vm.stats.vm.v_wire_count"+ , "vm.stats.vm.v_cache_count"]++ let [ pagesize, totalpages, freepages, activepages, inactivepages, wiredpages, cachedpages ] = fmap fromIntegral stats+ usedpages = activepages + wiredpages + cachedpages+ availablepages = inactivepages + cachedpages + freepages+ bufferedpages = activepages + inactivepages + wiredpages++ available = availablepages * pagesize+ used = usedpages * pagesize+ free = freepages * pagesize+ cache = cachedpages * pagesize+ buffer = bufferedpages * pagesize+ total = totalpages * pagesize++ usedratio = usedpages / totalpages+ freeratio = freepages / totalpages+ availableratio = availablepages / totalpages++ return [usedratio, freeratio, availableratio, total, free, buffer, cache, available, used]
+ src/Xmobar/Plugins/Monitors/Mem/Linux.hs view
@@ -0,0 +1,33 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Mem.Linux+-- Copyright : (c) Andrea Rossato+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A memory monitor for Xmobar+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Mem.Linux (parseMEM) where++import qualified Data.Map as M++fileMEM :: IO String+fileMEM = readFile "/proc/meminfo"++parseMEM :: IO [Float]+parseMEM =+ do file <- fileMEM+ let content = map words $ take 8 $ lines file+ info = M.fromList $ map (\line -> (head line, (read $ line !! 1 :: Float) / 1024)) content+ [total, free, buffer, cache] = map (info M.!) ["MemTotal:", "MemFree:", "Buffers:", "Cached:"]+ available = M.findWithDefault (free + buffer + cache) "MemAvailable:" info+ used = total - available+ usedratio = used / total+ freeratio = free / total+ availableratio = available / total+ return [usedratio, freeratio, availableratio, total, free, buffer, cache, available, used]
src/Xmobar/Plugins/Monitors/Net.hs view
@@ -11,9 +11,10 @@ -- -- A net device monitor for Xmobar --+ ----------------------------------------------------------------------------- -{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-} module Xmobar.Plugins.Monitors.Net ( startNet@@ -21,19 +22,19 @@ ) where import Xmobar.Plugins.Monitors.Common--import Data.IORef (IORef, newIORef, readIORef, writeIORef)-import Data.Time.Clock (UTCTime, getCurrentTime, diffUTCTime)-import Data.Word (Word64)-import Control.Monad (forM, filterM)-import System.Directory (getDirectoryContents, doesFileExist)-import System.FilePath ((</>))+import Xmobar.Plugins.Monitors.Net.Common (NetDev(..), NetDevInfo(..), NetDevRate, NetDevRef)+import Data.IORef (newIORef, readIORef, writeIORef)+import Data.Time.Clock (getCurrentTime, diffUTCTime) import System.Console.GetOpt-import System.IO.Error (catchIOError)-import System.IO.Unsafe (unsafeInterleaveIO) -import qualified Data.ByteString.Char8 as B+#if defined(freebsd_HOST_OS)+import qualified Xmobar.Plugins.Monitors.Net.FreeBSD as MN+#else+import qualified Xmobar.Plugins.Monitors.Net.Linux as MN+#endif +import Control.Monad (forM)+ type DevList = [String] parseDevList :: String -> DevList@@ -79,70 +80,11 @@ show MBs = "MB/s" show GBs = "GB/s" -data NetDev num = N String (NetDevInfo num) | NA deriving (Eq,Show,Read)-data NetDevInfo num = NI | ND num num deriving (Eq,Show,Read)--type NetDevRawTotal = NetDev Word64-type NetDevRate = NetDev Float--type NetDevRef = IORef (NetDevRawTotal, UTCTime)---- The more information available, the better.--- Note that names don't matter. Therefore, if only the names differ,--- a compare evaluates to EQ while (==) evaluates to False.-instance Ord num => Ord (NetDev num) where- compare NA NA = EQ- compare NA _ = LT- compare _ NA = GT- compare (N _ i1) (N _ i2) = i1 `compare` i2--instance Ord num => Ord (NetDevInfo num) where- compare NI NI = EQ- compare NI ND {} = LT- compare ND {} NI = GT- compare (ND x1 y1) (ND x2 y2) = x1 `compare` x2 <> y1 `compare` y2- netConfig :: IO MConfig netConfig = mkMConfig "<dev>: <rx>KB|<tx>KB" -- template ["dev", "rx", "tx", "rxbar", "rxvbar", "rxipat", "txbar", "txvbar", "txipat", "up"] -- available replacements -operstateDir :: String -> FilePath-operstateDir d = "/sys/class/net" </> d </> "operstate"--existingDevs :: IO [String]-existingDevs = getDirectoryContents "/sys/class/net" >>= filterM isDev- where isDev d | d `elem` excludes = return False- | otherwise = doesFileExist (operstateDir d)- excludes = [".", "..", "lo"]--isUp :: String -> IO Bool-isUp d = flip catchIOError (const $ return False) $ do- operstate <- B.readFile (operstateDir d)- return $! (head . B.lines) operstate `elem` ["up", "unknown"]--readNetDev :: [String] -> IO NetDevRawTotal-readNetDev ~[d, x, y] = do- up <- unsafeInterleaveIO $ isUp d- return $ N d (if up then ND (r x) (r y) else NI)- where r s | s == "" = 0- | otherwise = read s--netParser :: B.ByteString -> IO [NetDevRawTotal]-netParser = mapM (readNetDev . splitDevLine) . readDevLines- where readDevLines = drop 2 . B.lines- splitDevLine = map B.unpack . selectCols . filter (not . B.null) . B.splitWith (`elem` [' ',':'])- selectCols cols = map (cols!!) [0,1,9]--findNetDev :: String -> IO NetDevRawTotal-findNetDev dev = do- nds <- B.readFile "/proc/net/dev" >>= netParser- case filter isDev nds of- x:_ -> return x- _ -> return NA- where isDev (N d _) = d == dev- isDev NA = False- formatNet :: Maybe IconPattern -> Float -> Monitor (String, String, String, String) formatNet mipat d = do s <- getConfigValue useSuffix@@ -169,7 +111,7 @@ parseNet :: NetDevRef -> String -> IO NetDevRate parseNet nref nd = do (n0, t0) <- readIORef nref- n1 <- findNetDev nd+ n1 <- MN.findNetDev nd t1 <- getCurrentTime writeIORef nref (n1, t1) let scx = realToFrac (diffUTCTime t1 t0)@@ -213,7 +155,7 @@ startDynNet :: [String] -> Int -> (String -> IO ()) -> IO () startDynNet a r cb = do- devs <- existingDevs+ devs <- MN.existingDevs refs <- forM devs $ \d -> do t <- getCurrentTime nref <- newIORef (NA, t)
+ src/Xmobar/Plugins/Monitors/Net/Common.hs view
@@ -0,0 +1,50 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Net.Common+-- Copyright : (c) 2011, 2012, 2013, 2014, 2017, 2020 Jose Antonio Ortega Ruiz+-- (c) 2007-2010 Andrea Rossato+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A net device monitor for Xmobar+--++-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Net.Common (+ NetDev(..)+ , NetDevInfo(..)+ , NetDevRawTotal+ , NetDevRate+ , NetDevRef+ ) where++import Data.IORef (IORef)+import Data.Time.Clock (UTCTime)+import Data.Word (Word64)++data NetDev num = N String (NetDevInfo num) | NA deriving (Eq,Show,Read)+data NetDevInfo num = NI | ND num num deriving (Eq,Show,Read)++type NetDevRawTotal = NetDev Word64+type NetDevRate = NetDev Float++type NetDevRef = IORef (NetDevRawTotal, UTCTime)++-- The more information available, the better.+-- Note that names don't matter. Therefore, if only the names differ,+-- a compare evaluates to EQ while (==) evaluates to False.+instance Ord num => Ord (NetDev num) where+ compare NA NA = EQ+ compare NA _ = LT+ compare _ NA = GT+ compare (N _ i1) (N _ i2) = i1 `compare` i2++instance Ord num => Ord (NetDevInfo num) where+ compare NI NI = EQ+ compare NI ND {} = LT+ compare ND {} NI = GT+ compare (ND x1 y1) (ND x2 y2) = x1 `compare` x2 <> y1 `compare` y2
+ src/Xmobar/Plugins/Monitors/Net/FreeBSD.hsc view
@@ -0,0 +1,118 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE CApiFFI #-}++-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Net.FreeBSD+-- Copyright : (c) 2011, 2012, 2013, 2014, 2017, 2020 Jose Antonio Ortega Ruiz+-- (c) 2007-2010 Andrea Rossato+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A net device monitor for Xmobar+--++-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Net.FreeBSD (+ existingDevs+ , findNetDev+ ) where++import Xmobar.Plugins.Monitors.Net.Common (NetDevRawTotal, NetDev(..), NetDevInfo(..))+import Control.Exception (catch, SomeException(..))+import Foreign (Int32, plusPtr)+import Foreign.C.Types (CUIntMax, CUChar)+import Foreign.C.String (peekCString)+import Foreign.ForeignPtr ()+import Foreign.Storable (Storable, alignment, sizeOf, peek, poke)+import System.BSD.Sysctl (OID, sysctlPrepareOid, sysctlReadInt, sysctlPeek)++#include <sys/sysctl.h>+#include <net/if.h>+#include <net/if_mib.h>++data IfData = AvailableIfData {+ name :: String+ , txBytes :: CUIntMax+ , rxBytes :: CUIntMax+ , isUp :: Bool+ } | NotAvailableIfData+ deriving (Show, Read, Eq)++instance Storable IfData where+ alignment _ = #{alignment struct ifmibdata}+ sizeOf _ = #{size struct ifmibdata}+ peek ptr = do+ cname <- peekCString (ptr `plusPtr` (#offset struct ifmibdata, ifmd_name))+ tx <- peek ((ifmd_data_ptr ptr) `plusPtr` (#offset struct if_data, ifi_obytes)) :: IO CUIntMax+ rx <- peek ((ifmd_data_ptr ptr) `plusPtr` (#offset struct if_data, ifi_ibytes)) :: IO CUIntMax+ state <- peek ((ifmd_data_ptr ptr) `plusPtr` (#offset struct if_data, ifi_link_state)) :: IO CUChar+ return $ AvailableIfData {name = cname, txBytes = tx, rxBytes = rx, isUp = up state}+ where+ up state = state == (#const LINK_STATE_UP)+ ifmd_data_ptr p = p `plusPtr` (#offset struct ifmibdata, ifmd_data)++ poke _ _ = pure ()++getNetIfCountOID :: IO OID+getNetIfCountOID = sysctlPrepareOid [+ #const CTL_NET+ , #const PF_LINK+ , #const NETLINK_GENERIC+ , #const IFMIB_SYSTEM+ , #const IFMIB_IFCOUNT]++getNetIfDataOID :: Int32 -> IO OID+getNetIfDataOID i = sysctlPrepareOid [+ #const CTL_NET+ , #const PF_LINK+ , #const NETLINK_GENERIC+ , #const IFMIB_IFDATA+ , i+ , #const IFDATA_GENERAL]++getNetIfCount :: IO Int32+getNetIfCount = do+ oid <- getNetIfCountOID+ sysctlReadInt oid++getNetIfData :: Int32 -> IO IfData+getNetIfData i = do+ oid <- getNetIfDataOID i+ res <- catch (sysctlPeek oid) (\(SomeException _) -> return NotAvailableIfData)+ return res++getAllNetworkData :: IO [IfData]+getAllNetworkData = do+ count <- getNetIfCount+ result <- mapM getNetIfData [1..count]+ return result++existingDevs :: IO [String]+existingDevs = getAllNetworkData >>= (\xs -> return $ filter (/= "lo0") $ fmap name xs)++convertIfDataToNetDev :: IfData -> IO NetDevRawTotal+convertIfDataToNetDev ifData = do+ let up = isUp ifData+ rx = fromInteger . toInteger $ rxBytes ifData+ tx = fromInteger . toInteger $ txBytes ifData+ d = name ifData+ return $ N d (if up then ND rx tx else NI)++netConvertIfDataToNetDev :: [IfData] -> IO [NetDevRawTotal]+netConvertIfDataToNetDev = mapM convertIfDataToNetDev++findNetDev :: String -> IO NetDevRawTotal+findNetDev dev = do+ nds <- getAllNetworkData >>= netConvertIfDataToNetDev+ case filter isDev nds of+ x:_ -> return x+ _ -> return NA+ where isDev (N d _) = d == dev+ isDev NA = False
+ src/Xmobar/Plugins/Monitors/Net/Linux.hs view
@@ -0,0 +1,69 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Net.Linux+-- Copyright : (c) 2011, 2012, 2013, 2014, 2017, 2020 Jose Antonio Ortega Ruiz+-- (c) 2007-2010 Andrea Rossato+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A net device monitor for Xmobar+--++-----------------------------------------------------------------------------++{-# LANGUAGE OverloadedStrings #-}++module Xmobar.Plugins.Monitors.Net.Linux (+ existingDevs+ , findNetDev+ ) where++import Xmobar.Plugins.Monitors.Net.Common (NetDevRawTotal, NetDev(..), NetDevInfo(..))++import Control.Monad (filterM)+import System.Directory (getDirectoryContents, doesFileExist)+import System.FilePath ((</>))+import System.IO.Error (catchIOError)+import System.IO.Unsafe (unsafeInterleaveIO)++import qualified Data.ByteString.Char8 as B+++operstateDir :: String -> FilePath+operstateDir d = "/sys/class/net" </> d </> "operstate"++existingDevs :: IO [String]+existingDevs = getDirectoryContents "/sys/class/net" >>= filterM isDev+ where isDev d | d `elem` excludes = return False+ | otherwise = doesFileExist (operstateDir d)+ excludes = [".", "..", "lo"]++isUp :: String -> IO Bool+isUp d = flip catchIOError (const $ return False) $ do+ operstate <- B.readFile (operstateDir d)+ return $! (head . B.lines) operstate `elem` ["up", "unknown"]++readNetDev :: [String] -> IO NetDevRawTotal+readNetDev ~[d, x, y] = do+ up <- unsafeInterleaveIO $ isUp d+ return $ N d (if up then ND (r x) (r y) else NI)+ where r s | s == "" = 0+ | otherwise = read s++netParser :: B.ByteString -> IO [NetDevRawTotal]+netParser = mapM (readNetDev . splitDevLine) . readDevLines+ where readDevLines = drop 2 . B.lines+ splitDevLine = map B.unpack . selectCols . filter (not . B.null) . B.splitWith (`elem` [' ',':'])+ selectCols cols = map (cols!!) [0,1,9]++findNetDev :: String -> IO NetDevRawTotal+findNetDev dev = do+ nds <- B.readFile "/proc/net/dev" >>= netParser+ case filter isDev nds of+ x:_ -> return x+ _ -> return NA+ where isDev (N d _) = d == dev+ isDev NA = False
src/Xmobar/Plugins/Monitors/Swap.hs view
@@ -1,3 +1,4 @@+{-#LANGUAGE CPP #-} ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Swap@@ -16,31 +17,17 @@ import Xmobar.Plugins.Monitors.Common -import qualified Data.ByteString.Lazy.Char8 as B+#if defined(freebsd_HOST_OS)+import qualified Xmobar.Plugins.Monitors.Swap.FreeBSD as MS+#else+import qualified Xmobar.Plugins.Monitors.Swap.Linux as MS+#endif swapConfig :: IO MConfig swapConfig = mkMConfig "Swap: <usedratio>%" -- template ["usedratio", "total", "used", "free"] -- available replacements -fileMEM :: IO B.ByteString-fileMEM = B.readFile "/proc/meminfo"--parseMEM :: IO [Float]-parseMEM =- do file <- fileMEM- let li i l- | l /= [] = head l !! i- | otherwise = B.empty- fs s l- | null l = False- | otherwise = head l == B.pack s- get_data s = flip (/) 1024 . read . B.unpack . li 1 . filter (fs s)- st = map B.words . B.lines $ file- tot = get_data "SwapTotal:" st- free = get_data "SwapFree:" st- return [(tot - free) / tot, tot, tot - free, free]- formatSwap :: [Float] -> Monitor [String] formatSwap (r:xs) = do d <- getConfigValue decDigits@@ -51,6 +38,6 @@ runSwap :: [String] -> Monitor String runSwap _ =- do m <- io parseMEM+ do m <- io MS.parseMEM l <- formatSwap m parseTemplate l
+ src/Xmobar/Plugins/Monitors/Swap/FreeBSD.hsc view
@@ -0,0 +1,102 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Swap.FreeBSD+-- Copyright : (c) Andrea Rossato+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A swap usage monitor for Xmobar+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Swap.FreeBSD (parseMEM) where++import System.BSD.Sysctl (sysctlReadUInt)+import Foreign+import Foreign.C.Types+import Foreign.C.String++++#include <unistd.h>+#include <fcntl.h>+#include <kvm.h>+#include <limits.h>+#include <paths.h>+#include <stdlib.h>+++foreign import ccall unsafe "kvm.h kvm_open" c_kvm_open :: CString -> CString -> CString -> CInt -> CString -> IO (Ptr KVM_T)+foreign import ccall "&kvm_close" c_kvm_close :: FinalizerPtr KVM_T+foreign import ccall unsafe "kvm.h kvm_getswapinfo" c_kvm_getswapinfo :: Ptr KVM_T -> Ptr KVM_SWAP -> CInt -> CInt -> IO CInt++data KVM_T+data KvmT = KvmT !(ForeignPtr KVM_T)+ deriving (Eq, Ord, Show)++data KVM_SWAP+data KvmSwap = KvmSwap !(ForeignPtr KVM_SWAP)+ deriving (Eq, Ord, Show)++getKvmT:: IO KvmT+getKvmT = do+ withCString "/dev/null" $ \dir -> do+ kvm_t_ptr <- c_kvm_open nullPtr dir nullPtr #{const O_RDONLY} nullPtr+ ptr <- newForeignPtr c_kvm_close kvm_t_ptr+ return $ KvmT ptr++getSwapData :: KvmT -> IO SwapData+getSwapData (KvmT kvm_t_fp) = do+ withForeignPtr kvm_t_fp $ \kvm_t_ptr -> do+ allocaBytes #{size struct kvm_swap} $ \swap_ptr -> do+ c_kvm_getswapinfo kvm_t_ptr swap_ptr 1 0+ peek $ castPtr swap_ptr :: IO SwapData++data SwapData = AvailableSwapData {+ used :: Integer+ , total :: Integer+ } | NotAvailableSwapData+ deriving (Show, Read, Eq)++instance Storable SwapData where+ alignment _ = #{alignment struct kvm_swap}+ sizeOf _ = #{size struct kvm_swap}+ peek ptr = do+ cused <- #{peek struct kvm_swap, ksw_used} ptr :: IO CUInt+ ctotal <- #{peek struct kvm_swap, ksw_total} ptr :: IO CUInt+ return $ AvailableSwapData {used = toInteger cused, total = toInteger ctotal}++ poke _ _ = pure ()+++isEnabled :: IO Bool+isEnabled = do+ enabled <- sysctlReadUInt "vm.swap_enabled"+ return $ enabled == 1++parseMEM' :: Bool -> IO [Float]+parseMEM' False = return []+parseMEM' True = do+ kvm_t <- getKvmT+ swap <- getSwapData kvm_t+ pagesize <- toInteger <$> sysctlReadUInt "vm.stats.vm.v_page_size"++ let+ swapTotal = total swap+ swapUsed = used swap+ tot = swapTotal * pagesize+ fr = tot - swapUsed * pagesize++ return $ res (fromInteger tot) (fromInteger fr)+ where+ res :: Float -> Float -> [Float]+ res _ 0 = []+ res t f = [(t-f)/t, t, t - f, f]++parseMEM :: IO [Float]+parseMEM = do+ enabled <- isEnabled+ parseMEM' enabled
+ src/Xmobar/Plugins/Monitors/Swap/Linux.hs view
@@ -0,0 +1,35 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Swap.Linux+-- Copyright : (c) Andrea Rossato+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- A swap usage monitor for Xmobar+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Swap.Linux (parseMEM) where++import qualified Data.ByteString.Lazy.Char8 as B++fileMEM :: IO B.ByteString+fileMEM = B.readFile "/proc/meminfo"++parseMEM :: IO [Float]+parseMEM =+ do file <- fileMEM+ let li i l+ | l /= [] = head l !! i+ | otherwise = B.empty+ fs s l+ | null l = False+ | otherwise = head l == B.pack s+ get_data s = flip (/) 1024 . read . B.unpack . li 1 . filter (fs s)+ st = map B.words . B.lines $ file+ tot = get_data "SwapTotal:" st+ free = get_data "SwapFree:" st+ return [(tot - free) / tot, tot, tot - free, free]
src/Xmobar/Plugins/Monitors/Top.hs view
@@ -1,3 +1,5 @@+{-#LANGUAGE CPP #-}+{-# LANGUAGE BangPatterns #-} ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Top@@ -12,25 +14,28 @@ -- ----------------------------------------------------------------------------- -{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE BangPatterns #-}- module Xmobar.Plugins.Monitors.Top (startTop, topMemConfig, runTopMem) where import Xmobar.Plugins.Monitors.Common -import Control.Exception (SomeException, handle)-import Data.IORef (IORef, newIORef, readIORef, writeIORef)-import Data.List (sortBy, foldl')+import Data.IORef (newIORef, readIORef, writeIORef)+import Data.List (sortBy) import Data.Ord (comparing)-import Data.Time.Clock (UTCTime, getCurrentTime, diffUTCTime)-import System.Directory (getDirectoryContents)-import System.FilePath ((</>))-import System.IO (IOMode(ReadMode), hGetLine, withFile)-import System.Posix.Unistd (SysVar(ClockTick), getSysVar)+import Data.Time.Clock (getCurrentTime, diffUTCTime) -import Foreign.C.Types+import Xmobar.Plugins.Monitors.Top.Common (+ MemInfo+ , TimeInfo+ , Times+ , TimesRef) +#if defined(freebsd_HOST_OS)+import qualified Xmobar.Plugins.Monitors.Top.FreeBSD as MT+#else+import qualified Xmobar.Plugins.Monitors.Top.Linux as MT+#endif++ maxEntries :: Int maxEntries = 10 @@ -47,41 +52,6 @@ , k <- [ "name", "cpu", "both" , "mname", "mem", "mboth"]]) -foreign import ccall "unistd.h getpagesize"- c_getpagesize :: CInt--pageSize :: Float-pageSize = fromIntegral c_getpagesize / 1024--processes :: IO [FilePath]-processes = fmap (filter isPid) (getDirectoryContents "/proc")- where isPid = (`elem` ['0'..'9']) . head--statWords :: [String] -> [String]-statWords line@(x:pn:ppn:xs) =- if last pn == ')' then line else statWords (x:(pn ++ " " ++ ppn):xs)-statWords _ = replicate 52 "0"--getProcessData :: FilePath -> IO [String]-getProcessData pidf =- handle ign $ withFile ("/proc" </> pidf </> "stat") ReadMode readWords- where readWords = fmap (statWords . words) . hGetLine- ign = const (return []) :: SomeException -> IO [String]--memPages :: [String] -> String-memPages fs = fs!!23--ppid :: [String] -> String-ppid fs = fs!!3--skip :: [String] -> Bool-skip fs = length fs < 24 || memPages fs == "0" || ppid fs == "0"--handleProcesses :: ([String] -> a) -> IO [a]-handleProcesses f =- fmap (foldl' (\a p -> if skip p then a else f p : a) [])- (processes >>= mapM getProcessData)- showInfo :: String -> String -> Float -> Monitor [String] showInfo nm sms mms = do mnw <- getConfigValue maxWidth@@ -94,20 +64,10 @@ both <- showWithColors' (rnm ++ " " ++ sms) mms return [nm, mstr, both] -processName :: [String] -> String-processName = drop 1 . init . (!!1) sortTop :: [(String, Float)] -> [(String, Float)] sortTop = sortBy (flip (comparing snd)) -type MemInfo = (String, Float)--meminfo :: [String] -> MemInfo-meminfo fs = (processName fs, pageSize * parseFloat (fs!!23))--meminfos :: IO [MemInfo]-meminfos = handleProcesses meminfo- showMemInfo :: Float -> MemInfo -> Monitor [String] showMemInfo scale (nm, rss) = showInfo nm (showWithUnits 3 1 rss) (100 * rss / sc)@@ -117,30 +77,8 @@ showMemInfos ms = mapM (showMemInfo tm) ms where tm = sum (map snd ms) -runTopMem :: [String] -> Monitor String-runTopMem _ = do- mis <- io meminfos- pstr <- showMemInfos (sortTop mis)- parseTemplate $ concat pstr--type Pid = Int-type TimeInfo = (String, Float)-type TimeEntry = (Pid, TimeInfo)-type Times = [TimeEntry]-type TimesRef = IORef (Times, UTCTime)--timeMemEntry :: [String] -> (TimeEntry, MemInfo)-timeMemEntry fs = ((p, (n, t)), (n, r))- where p = parseInt (head fs)- n = processName fs- t = parseFloat (fs!!13) + parseFloat (fs!!14)- (_, r) = meminfo fs--timeMemEntries :: IO [(TimeEntry, MemInfo)]-timeMemEntries = handleProcesses timeMemEntry- timeMemInfos :: IO (Times, [MemInfo], Int)-timeMemInfos = fmap res timeMemEntries+timeMemInfos = fmap res MT.timeMemEntries where res x = (sortBy (comparing fst) $ map fst x, map snd x, length x) combine :: Times -> Times -> Times@@ -164,7 +102,7 @@ c1 <- getCurrentTime let scx = realToFrac (diffUTCTime c1 c0) * scale !scx' = if scx > 0 then scx else scale- nts = map (\(_, (nm, t)) -> (nm, min 100 (t / scx'))) (combine t0 t1)+ nts = map (\(_, (nm, t)) -> (nm, t / scx')) (combine t0 t1) !t1' = take' (length t1) t1 !nts' = take' maxEntries (sortTop nts) !mis' = take' maxEntries (sortTop mis)@@ -178,6 +116,12 @@ showTimeInfos :: [TimeInfo] -> Monitor [[String]] showTimeInfos = mapM showTimeInfo +runTopMem :: [String] -> Monitor String+runTopMem _ = do+ mis <- io MT.meminfos+ pstr <- showMemInfos (sortTop mis)+ parseTemplate $ concat pstr+ runTop :: TimesRef -> Float -> [String] -> Monitor String runTop tref scale _ = do (no, ps, ms) <- io $ topProcesses tref scale@@ -187,9 +131,8 @@ startTop :: [String] -> Int -> (String -> IO ()) -> IO () startTop a r cb = do- cr <- getSysVar ClockTick c <- getCurrentTime tref <- newIORef ([], c)- let scale = fromIntegral cr / 100+ scale <- MT.scale _ <- topProcesses tref scale runM a topConfig (runTop tref scale) r cb
+ src/Xmobar/Plugins/Monitors/Top/Common.hs view
@@ -0,0 +1,32 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Top.Common+-- Copyright : (c) 2010, 2011, 2012, 2013, 2014, 2018 Jose A Ortega Ruiz+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- Process activity and memory consumption monitors+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Top.Common (+ MemInfo+ , Pid+ , TimeInfo+ , TimeEntry+ , Times+ , TimesRef+ ) where++import Data.IORef (IORef)+import Data.Time.Clock (UTCTime)++type MemInfo = (String, Float)+type Pid = Int+type TimeInfo = (String, Float)+type TimeEntry = (Pid, TimeInfo)+type Times = [TimeEntry]+type TimesRef = IORef (Times, UTCTime)
+ src/Xmobar/Plugins/Monitors/Top/FreeBSD.hsc view
@@ -0,0 +1,143 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CApiFFI #-}++-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Top.FreeBSD+-- Copyright : (c) 2010, 2011, 2012, 2013, 2014, 2018 Jose A Ortega Ruiz+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- Process activity and memory consumption monitors+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.Monitors.Top.FreeBSD (+ timeMemEntries+ , meminfos+ , scale) where++import Foreign+import Foreign.C.Types+import Foreign.C.String++import Xmobar.Plugins.Monitors.Top.Common (MemInfo, TimeEntry)++#include <unistd.h>+#include <sys/sysctl.h>+#include <sys/user.h>+#include <libprocstat.h>++foreign import ccall "unistd.h getpagesize" c_getpagesize :: CInt+foreign import ccall unsafe "libprocstat.h procstat_open_sysctl" c_procstat_open_sysctl :: IO (Ptr PROCSTAT)+foreign import ccall "&procstat_close" c_procstat_close :: FinalizerPtr PROCSTAT+foreign import ccall "&procstat_freeprocs" c_procstat_freeprocs :: FinalizerEnvPtr PROCSTAT KINFO_PROC+foreign import ccall unsafe "libprocstat.h procstat_getprocs" c_procstat_getprocs :: Ptr PROCSTAT -> CInt -> CInt -> Ptr CUInt -> IO (Ptr KINFO_PROC)++data PROCSTAT+data ProcStat = ProcStat !(ForeignPtr PROCSTAT)+ deriving (Eq, Ord, Show)++data KINFO_PROC+data KinfoProc = KinfoProc [ProcData] Int+ deriving (Eq, Show)++data ProcData = ProcData {+ pname :: String+ , cpu :: Float+ , tdflags :: CULong+ , flag :: CULong+ , stat :: CUChar+ , rss :: Float+ , pid :: Int+ , runtime :: Float+ }+ deriving (Show, Read, Eq)++instance Storable ProcData where+ alignment _ = #{alignment struct kinfo_proc}+ sizeOf _ = #{size struct kinfo_proc}+ peek ptr = do+ c <- #{peek struct kinfo_proc, ki_pctcpu} ptr+ ctdflags <- #{peek struct kinfo_proc, ki_tdflags} ptr+ cflag <- #{peek struct kinfo_proc, ki_flag} ptr+ cstat <- #{peek struct kinfo_proc, ki_stat} ptr+ cruntime <- #{peek struct kinfo_proc, ki_runtime} ptr :: IO CULong+ crss <- #{peek struct kinfo_proc, ki_rssize} ptr :: IO CULong+ cname <- peekCString (ptr `plusPtr` (#offset struct kinfo_proc, ki_comm))+ cpid <- #{peek struct kinfo_proc, ki_pid} ptr+ let crssf = (fromIntegral . toInteger) crss+ let cruntimef = ((fromIntegral . toInteger) cruntime + 500000) / 10000+ return $ ProcData {+ pname = cname+ , cpu = (pctdouble c) * 100+ , tdflags = ctdflags+ , stat = cstat+ , flag = cflag+ , rss = crssf * pageSize+ , pid = cpid+ , runtime = cruntimef}++ poke _ _ = pure ()++pctdouble :: Int -> Float+pctdouble p = (fromIntegral p) / #{const FSCALE}+++pageSize :: Float+pageSize = fromIntegral c_getpagesize / 1024+++getProcStat:: IO ProcStat+getProcStat = do+ proc_ptr <- c_procstat_open_sysctl+ ptr <- newForeignPtr c_procstat_close proc_ptr+ return $ ProcStat ptr+++getProcessesInfo :: ProcStat -> IO [ProcData]+getProcessesInfo (ProcStat ps_fp) = do+ withForeignPtr ps_fp $ \ps_ptr -> do+ alloca $ \n_ptr -> do+ kinfo_proc_ptr <- c_procstat_getprocs ps_ptr #{const KERN_PROC_PROC} 0 n_ptr+ newForeignPtrEnv c_procstat_freeprocs ps_ptr kinfo_proc_ptr+ num <- peek (n_ptr :: Ptr CUInt)+ pds <- peekArray (fromIntegral num) $ castPtr kinfo_proc_ptr :: IO [ProcData]++ return $ [p | p <- pds, flag p .&. #{const P_SYSTEM} == 0]+++processes :: IO [ProcData]+processes = do+ proc_stat <- getProcStat+ getProcessesInfo proc_stat++handleProcesses :: (ProcData -> a) -> IO [a]+handleProcesses f = do+ ps <- processes+ return $ fmap (\pd -> f pd) ps++meminfo :: ProcData -> MemInfo+meminfo pd = (pname pd, rss pd)++meminfos :: IO [MemInfo]+meminfos = handleProcesses meminfo++timeMemEntry :: ProcData -> (TimeEntry, MemInfo)+timeMemEntry pd = ((p, (n, t)), (n, r))+ where p = pid pd+ n = pname pd+ t = runtime pd+ (_, r) = meminfo pd++timeMemEntries :: IO [(TimeEntry, MemInfo)]+timeMemEntries = handleProcesses timeMemEntry++scale :: IO Float+scale = return 1
+ src/Xmobar/Plugins/Monitors/Top/Linux.hs view
@@ -0,0 +1,92 @@+-----------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Top.Linux+-- Copyright : (c) 2010, 2011, 2012, 2013, 2014, 2018 Jose A Ortega Ruiz+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Jose A Ortega Ruiz <jao@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- Process activity and memory consumption monitors+--+-----------------------------------------------------------------------------++{-# LANGUAGE ForeignFunctionInterface #-}++module Xmobar.Plugins.Monitors.Top.Linux (+ timeMemEntries+ , meminfos+ , scale) where++import Xmobar.Plugins.Monitors.Common (parseFloat, parseInt)+import Xmobar.Plugins.Monitors.Top.Common (MemInfo, TimeEntry)++import Control.Exception (SomeException, handle)+import Data.List (foldl')+import System.Directory (getDirectoryContents)+import System.FilePath ((</>))+import System.IO (IOMode(ReadMode), hGetLine, withFile)+import System.Posix.Unistd (SysVar(ClockTick), getSysVar)++import Foreign.C.Types++foreign import ccall "unistd.h getpagesize"+ c_getpagesize :: CInt++pageSize :: Float+pageSize = fromIntegral c_getpagesize / 1024++processes :: IO [FilePath]+processes = fmap (filter isPid) (getDirectoryContents "/proc")+ where isPid = (`elem` ['0'..'9']) . head++statWords :: [String] -> [String]+statWords line@(x:pn:ppn:xs) =+ if last pn == ')' then line else statWords (x:(pn ++ " " ++ ppn):xs)+statWords _ = replicate 52 "0"++getProcessData :: FilePath -> IO [String]+getProcessData pidf =+ handle ign $ withFile ("/proc" </> pidf </> "stat") ReadMode readWords+ where readWords = fmap (statWords . words) . hGetLine+ ign = const (return []) :: SomeException -> IO [String]++memPages :: [String] -> String+memPages fs = fs!!23++ppid :: [String] -> String+ppid fs = fs!!3++skip :: [String] -> Bool+skip fs = length fs < 24 || memPages fs == "0" || ppid fs == "0"++handleProcesses :: ([String] -> a) -> IO [a]+handleProcesses f =+ fmap (foldl' (\a p -> if skip p then a else f p : a) [])+ (processes >>= mapM getProcessData)++processName :: [String] -> String+processName = drop 1 . init . (!!1)++meminfo :: [String] -> MemInfo+meminfo fs = (processName fs, pageSize * parseFloat (fs!!23))++meminfos :: IO [MemInfo]+meminfos = handleProcesses meminfo++timeMemEntry :: [String] -> (TimeEntry, MemInfo)+timeMemEntry fs = ((p, (n, t)), (n, r))+ where p = parseInt (head fs)+ n = processName fs+ t = parseFloat (fs!!13) + parseFloat (fs!!14)+ (_, r) = meminfo fs++timeMemEntries :: IO [(TimeEntry, MemInfo)]+timeMemEntries = handleProcesses timeMemEntry+++scale :: IO Float+scale = do+ cr <- getSysVar ClockTick+ return $ fromIntegral cr / 100
src/Xmobar/Plugins/Monitors/Uptime.hs view
@@ -1,3 +1,5 @@+{-#LANGUAGE CPP #-}+ ------------------------------------------------------------------------------ -- | -- Module : Plugins.Monitors.Uptime@@ -19,22 +21,22 @@ import Xmobar.Plugins.Monitors.Common -import qualified Data.ByteString.Lazy.Char8 as B+#if defined(freebsd_HOST_OS)+import qualified Xmobar.Plugins.Monitors.Uptime.FreeBSD as MU+#else+import qualified Xmobar.Plugins.Monitors.Uptime.Linux as MU+#endif uptimeConfig :: IO MConfig uptimeConfig = mkMConfig "Up <days>d <hours>h <minutes>m" ["days", "hours", "minutes", "seconds"] -readUptime :: IO Float-readUptime =- fmap (read . B.unpack . head . B.words) (B.readFile "/proc/uptime")- secsPerDay :: Integer secsPerDay = 24 * 3600 uptime :: Monitor [String] uptime = do- t <- io readUptime+ t <- io MU.readUptime u <- getConfigValue useSuffix let tsecs = floor t secs = tsecs `mod` secsPerDay
+ src/Xmobar/Plugins/Monitors/Uptime/FreeBSD.hsc view
@@ -0,0 +1,52 @@+------------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Uptime.FreeBSD+-- Copyright : (c) 2010 Jose Antonio Ortega Ruiz+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : jao@gnu.org+-- Stability : unstable+-- Portability : unportable+-- Created: Sun Dec 12, 2010 20:26+--+--+-- Uptime+--+------------------------------------------------------------------------------+++module Xmobar.Plugins.Monitors.Uptime.FreeBSD (readUptime) where++import Data.Time.Clock.POSIX (getPOSIXTime)+import System.BSD.Sysctl+import Data.Int+import Foreign.C+import Foreign.Storable++#include <sys/types.h>+#include <sys/user.h>+#include <sys/time.h>+#include <sys/sysctl.h>++data TimeVal = TimeVal {sec:: CTime}++instance Storable TimeVal where+ sizeOf _ = #{size struct timeval}+ alignment _ = alignment (undefined::CTime)+ peek ptr = do cSec <- #{peek struct timeval, tv_sec} ptr+ return (TimeVal cSec)+ poke _ _ = pure ()++now :: IO Int64+now = do+ posix <- getPOSIXTime+ return $ round posix++readUptime :: IO Float+readUptime = do+ tv <- sysctlPeek "kern.boottime" :: IO TimeVal+ nowSec <- now+ return $ fromInteger $ toInteger $ (nowSec - (secInt $ sec tv))+ where+ secInt :: CTime -> Int64+ secInt (CTime cSec) = cSec
+ src/Xmobar/Plugins/Monitors/Uptime/Linux.hs view
@@ -0,0 +1,24 @@+------------------------------------------------------------------------------+-- |+-- Module : Plugins.Monitors.Uptime.Linux+-- Copyright : (c) 2010 Jose Antonio Ortega Ruiz+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : jao@gnu.org+-- Stability : unstable+-- Portability : unportable+-- Created: Sun Dec 12, 2010 20:26+--+--+-- Uptime+--+------------------------------------------------------------------------------+++module Xmobar.Plugins.Monitors.Uptime.Linux (readUptime) where++import qualified Data.ByteString.Lazy.Char8 as B++readUptime :: IO Float+readUptime =+ fmap (read . B.unpack . head . B.words) (B.readFile "/proc/uptime")
+ src/Xmobar/Plugins/QueueReader.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE RecordWildCards #-}+module Xmobar.Plugins.QueueReader+ (QueueReader (..)+ ) where++import Xmobar.Run.Exec (Exec (..))++import Control.Monad (forever)+import qualified Control.Concurrent.STM as STM++-- | A 'QueueReader' displays data from an 'TQueue a' where+-- the data items 'a' are rendered by a user supplied function.+--+-- Like the 'HandleReader' plugin this is only useful if you are+-- running @xmobar@ from other Haskell code. You should create a+-- new @TQueue a@ and pass it to this plugin.+--+-- @+-- main :: IO+-- main = do+-- q <- STM.newQueueIO @String+-- bar <- forkIO $ xmobar conf+-- { commands = Run (QueueReader q id "Queue") : commands conf }+-- STM.atomically $ STM.writeTQueue q "Some Message"+-- @+data QueueReader a+ = QueueReader+ { qQueue :: STM.TQueue a+ , qShowItem :: a -> String+ , qName :: String+ }++-- | This cannot be read back.+instance Show (QueueReader a) where+ -- | Only show the name/alias for the queue reader.+ show q = "QueueReader " <> qName q++-- | WARNING: This read instance will throw an exception if used! It is+-- only implemented, because it is required by 'Xmobar.Run` in 'Xmobar.commands'.+instance Read (QueueReader a) where+ -- | Throws an 'error'!+ readsPrec = error "QueueReader: instance is a stub"++-- | Async queue/channel reading.+instance Exec (QueueReader a) where+ -- | Read from queue as data arrives.+ start QueueReader{..} cb =+ forever (STM.atomically (qShowItem <$> STM.readTQueue qQueue) >>= cb)++ alias = qName
src/Xmobar/X11/Actions.hs view
@@ -18,7 +18,7 @@ import Graphics.X11.Types (Button) data Action = Spawn [Button] String- deriving (Eq)+ deriving (Eq, Show) runAction :: Action -> IO () runAction (Spawn _ s) = void $ system (s ++ "&")
src/Xmobar/X11/Draw.hs view
@@ -60,6 +60,7 @@ getWidth (Text s,cl,i,_) = 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)+ getWidth (Hspace p,cl,i,_) = return (Hspace p,cl,i,fi p) p <- liftIO $ createPixmap d w wid ht (defaultDepthOfScreen (defaultScreenOfDisplay d))@@ -102,6 +103,7 @@ verticalOffset ht (Icon _) _ _ conf | iconOffset conf > -1 = return $ fi (iconOffset conf) | otherwise = return $ fi (ht `div` 2) - 1+verticalOffset _ (Hspace _) _ voffs _ = return $ fi voffs printString :: Display -> Drawable -> XFont -> GC -> String -> String -> Position -> Position -> Position -> Position -> String -> Int -> IO ()@@ -160,6 +162,7 @@ (Icon p) -> liftIO $ maybe (return ()) (B.drawBitmap d dr gc fc bc offset valign) (lookup p (iconS r))+ (Hspace _) -> liftIO $ return () let triBoxes = tBoxes c dropBoxes = filter (\(_,b) -> b `notElem` triBoxes) boxes boxes' = map (\((x1,_),b) -> ((x1, offset + l), b)) (filter (\(_,b) -> b `elem` triBoxes) boxes)
src/Xmobar/X11/Parsers.hs view
@@ -28,11 +28,11 @@ import Graphics.X11.Types (Button) import Foreign.C.Types (CInt) -data Widget = Icon String | Text String+data Widget = Icon String | Text String | Hspace Int32 deriving Show -data BoxOffset = BoxOffset Align Int32 deriving Eq +data BoxOffset = BoxOffset Align Int32 deriving (Eq, Show) -- margins: Top, Right, Bottom, Left-data BoxMargins = BoxMargins Int32 Int32 Int32 Int32 deriving Eq+data BoxMargins = BoxMargins Int32 Int32 Int32 Int32 deriving (Eq, Show) data BoxBorder = BBTop | BBBottom | BBVBoth@@ -40,14 +40,14 @@ | BBRight | BBHBoth | BBFull- deriving ( Read, Eq )-data Box = Box BoxBorder BoxOffset CInt String BoxMargins deriving Eq+ deriving ( Read, Eq, Show )+data Box = Box BoxBorder BoxOffset CInt String BoxMargins deriving (Eq, Show) data TextRenderInfo = TextRenderInfo { tColorsString :: String , tBgTopOffset :: Int32 , tBgBottomOffset :: Int32 , tBoxes :: [Box]- }+ } deriving Show type FontIndex = Int -- | Runs the string parser@@ -68,6 +68,7 @@ -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])] allParsers c f a = textParser c f a <|> try (iconParser c f a)+ <|> try (hspaceParser c f a) <|> try (rawParser c f a) <|> try (actionParser c f a) <|> try (fontParser c a)@@ -91,6 +92,7 @@ try (string "action=") <|> try (string "/action>") <|> try (string "icon=") <|>+ try (string "hspace=") <|> try (string "raw=") <|> try (string "/fn>") <|> try (string "/box>") <|>@@ -132,6 +134,13 @@ string "<icon=" i <- manyTill (noneOf ">") (try (string "/>")) return [(Icon i, c, f, a)]++hspaceParser :: TextRenderInfo -> FontIndex -> Maybe [Action]+ -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]+hspaceParser c f a = do+ string "<hspace="+ pVal <- manyTill digit (try (string "/>"))+ return [(Hspace (fromMaybe 0 $ readMaybe pVal), c, f, a)] actionParser :: TextRenderInfo -> FontIndex -> Maybe [Action] -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]
xmobar.cabal view
@@ -1,5 +1,5 @@ name: xmobar-version: 0.39+version: 0.40 homepage: http://xmobar.org synopsis: A Minimalistic Text Based Status Bar description: Xmobar is a minimalistic text based status bar.@@ -140,6 +140,7 @@ Xmobar.Plugins.Date, Xmobar.Plugins.EWMH, Xmobar.Plugins.HandleReader,+ Xmobar.Plugins.QueueReader, Xmobar.Plugins.PipeReader, Xmobar.Plugins.MarqueePipeReader, Xmobar.Plugins.StdinReader,@@ -149,21 +150,25 @@ Xmobar.Plugins.NotmuchMail, Xmobar.Plugins.Monitors, Xmobar.Plugins.Monitors.Batt,+ Xmobar.Plugins.Monitors.Batt.Common, Xmobar.Plugins.Monitors.Common.Output, Xmobar.Plugins.Monitors.Common.Parsers, Xmobar.Plugins.Monitors.Common.Files, Xmobar.Plugins.Monitors.CoreTemp, Xmobar.Plugins.Monitors.K10Temp,+ Xmobar.Plugins.Monitors.Cpu.Common, Xmobar.Plugins.Monitors.CpuFreq, Xmobar.Plugins.Monitors.Disk, Xmobar.Plugins.Monitors.Mem, Xmobar.Plugins.Monitors.MultiCoreTemp, Xmobar.Plugins.Monitors.MultiCpu, Xmobar.Plugins.Monitors.Net,+ Xmobar.Plugins.Monitors.Net.Common, Xmobar.Plugins.Monitors.Swap, Xmobar.Plugins.Monitors.Thermal, Xmobar.Plugins.Monitors.ThermalZone, Xmobar.Plugins.Monitors.Top,+ Xmobar.Plugins.Monitors.Top.Common, Xmobar.Plugins.Monitors.Uptime, Xmobar.Plugins.Monitors.Bright, Xmobar.Plugins.Monitors.CatInt@@ -290,8 +295,24 @@ if os(freebsd) -- enables freebsd specific code+ extra-libraries: procstat+ , kvm build-depends: bsd-sysctl- cpp-options: -DFREEBSD+ other-modules: Xmobar.Plugins.Monitors.Batt.FreeBSD,+ Xmobar.Plugins.Monitors.Cpu.FreeBSD,+ Xmobar.Plugins.Monitors.Mem.FreeBSD,+ Xmobar.Plugins.Monitors.Net.FreeBSD,+ Xmobar.Plugins.Monitors.Swap.FreeBSD,+ Xmobar.Plugins.Monitors.Top.FreeBSD,+ Xmobar.Plugins.Monitors.Uptime.FreeBSD+ else+ other-modules: Xmobar.Plugins.Monitors.Batt.Linux,+ Xmobar.Plugins.Monitors.Cpu.Linux,+ Xmobar.Plugins.Monitors.Mem.Linux,+ Xmobar.Plugins.Monitors.Net.Linux,+ Xmobar.Plugins.Monitors.Swap.Linux,+ Xmobar.Plugins.Monitors.Top.Linux,+ Xmobar.Plugins.Monitors.Uptime.Linux executable xmobar default-language: Haskell2010@@ -352,6 +373,7 @@ Xmobar.Plugins.Monitors.Common.Output Xmobar.Plugins.Monitors.Common.Files Xmobar.Plugins.Monitors.Cpu+ Xmobar.Plugins.Monitors.Cpu.Common Xmobar.Plugins.Monitors.CpuSpec Xmobar.Plugins.Monitors.Common.Run Xmobar.Run.Exec@@ -367,6 +389,13 @@ Xmobar.Plugins.Monitors.AlsaSpec cpp-options: -DALSA++ if os(freebsd)+ -- enables freebsd specific code+ build-depends: bsd-sysctl+ other-modules: Xmobar.Plugins.Monitors.Cpu.FreeBSD+ else+ other-modules: Xmobar.Plugins.Monitors.Cpu.Linux benchmark xmobarbench type: exitcode-stdio-1.0