diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Xmobar/Config/Template.hs | 9 | ||||
-rw-r--r-- | src/Xmobar/Draw/Cairo.hs | 8 | ||||
-rw-r--r-- | src/Xmobar/Plugins/MarqueePipeReader.hs | 2 | ||||
-rw-r--r-- | src/Xmobar/Plugins/Monitors/Top.hs | 6 | ||||
-rw-r--r-- | src/Xmobar/Run/Actions.hs | 6 | ||||
-rw-r--r-- | src/Xmobar/Run/Exec.hs | 3 | ||||
-rw-r--r-- | src/Xmobar/Run/Loop.hs | 15 | ||||
-rw-r--r-- | src/Xmobar/Run/Runnable.hs | 1 | ||||
-rw-r--r-- | src/Xmobar/Text/Loop.hs | 11 | ||||
-rw-r--r-- | src/Xmobar/X11/Loop.hs | 56 |
10 files changed, 79 insertions, 38 deletions
diff --git a/src/Xmobar/Config/Template.hs b/src/Xmobar/Config/Template.hs index ad30c3d..6ea1898 100644 --- a/src/Xmobar/Config/Template.hs +++ b/src/Xmobar/Config/Template.hs @@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Config.Template --- Copyright: (c) 2022 jao +-- Copyright: (c) 2022, 2025 jao -- License: BSD3-style (see LICENSE) -- -- Maintainer: mail@jao.io @@ -15,7 +15,7 @@ ------------------------------------------------------------------------------ -module Xmobar.Config.Template (parseString) where +module Xmobar.Config.Template (parseString, withEmptyAction) where import Data.Maybe (fromMaybe) import qualified Control.Monad as CM @@ -101,11 +101,14 @@ hspaceParser c = do pVal <- C.manyTill P.digit (P.try (P.string "/>")) retSegment c (T.Hspace (fromMaybe 0 $ readMaybe pVal)) +withEmptyAction :: String -> String +withEmptyAction str = "<action=>" ++ str ++ "</action>" + actionParser :: Context -> Parser [T.Segment] actionParser (ti, fi, act) = do P.string "<action=" command <- C.between (P.char '`') (P.char '`') (C.many1 (P.noneOf "`")) - <|> C.many1 (P.noneOf ">") + <|> C.many1 (P.noneOf ">") <|> P.string "" buttons <- (P.char '>' >> return "1") <|> (P.space >> P.spaces >> C.between (P.string "button=") (P.string ">") (C.many1 (P.oneOf "12345"))) let a = T.Spawn (toButtons buttons) command diff --git a/src/Xmobar/Draw/Cairo.hs b/src/Xmobar/Draw/Cairo.hs index 2338b10..cc35631 100644 --- a/src/Xmobar/Draw/Cairo.hs +++ b/src/Xmobar/Draw/Cairo.hs @@ -2,7 +2,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.X11.Cairo --- Copyright: (c) 2022, 2023, 2024 Jose Antonio Ortega Ruiz +-- Copyright: (c) 2022, 2023, 2024, 2025 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org @@ -124,7 +124,9 @@ drawSegment :: T.DrawContext -> Surface -> Double -> Acc -> Renderinfo -> IO Acc drawSegment dctx surface maxoff (off, acts, boxs) (segment, render, lwidth) = do let end = min maxoff (off + lwidth) (_, info, _, a) = segment - acts' = case a of Just as -> (as, off, end):acts; _ -> acts + acts' = case a of + Just as -> (as, off, end):acts + _ -> ([], off, end):acts bs = C.tBoxes info boxs' = if null bs then boxs else (off, end, bs):boxs when (end > off) $ do @@ -193,4 +195,4 @@ drawSegments dctx surf = do (_, as'', bx'') <- foldM (drawSegment dctx surf dw) (rstart, as', bx') rlyts drawBoxes dctx surf (reverse bx'') when (C.borderWidth conf > 0) (drawBorder conf dw dh surf) - return as'' + return (reverse as'') diff --git a/src/Xmobar/Plugins/MarqueePipeReader.hs b/src/Xmobar/Plugins/MarqueePipeReader.hs index 075503c..a6d590e 100644 --- a/src/Xmobar/Plugins/MarqueePipeReader.hs +++ b/src/Xmobar/Plugins/MarqueePipeReader.hs @@ -60,7 +60,7 @@ writer txt sep len rate chan cb = do Nothing -> tenthSeconds rate >> writer (drop 1 txt) sep len rate chan cb toInfTxt :: String -> String -> String -toInfTxt line sep = concat (repeat $ line ++ " " ++ sep ++ " ") +toInfTxt line sep = cycle (line ++ " " ++ sep ++ " ") checkPipe :: FilePath -> IO () checkPipe file = handle (\(SomeException _) -> waitForPipe) $ do diff --git a/src/Xmobar/Plugins/Monitors/Top.hs b/src/Xmobar/Plugins/Monitors/Top.hs index 3bfe6fd..7066307 100644 --- a/src/Xmobar/Plugins/Monitors/Top.hs +++ b/src/Xmobar/Plugins/Monitors/Top.hs @@ -3,7 +3,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Top --- Copyright : (c) 2010, 2011, 2012, 2013, 2014, 2018, 2022 Jose A Ortega Ruiz +-- Copyright : (c) 2010, 2011, 2012, 2013, 2014, 2018, 2022, 2025 Jose A Ortega Ruiz -- License : BSD-style (see LICENSE) -- -- Maintainer : Jose A Ortega Ruiz <jao@gnu.org> @@ -20,7 +20,7 @@ import Xmobar.Plugins.Monitors.Common import Data.IORef (newIORef, readIORef, writeIORef) import Data.List (sortBy) -import Data.Ord (comparing) +import Data.Ord (comparing, Down (..)) import Data.Time.Clock (getCurrentTime, diffUTCTime) import Xmobar.Plugins.Monitors.Top.Common ( @@ -66,7 +66,7 @@ showInfo nm sms mms = do sortTop :: [(String, Float)] -> [(String, Float)] -sortTop = sortBy (flip (comparing snd)) +sortTop = sortBy (comparing (Down . snd)) showMemInfo :: Float -> MemInfo -> Monitor [String] showMemInfo scale (nm, rss) = diff --git a/src/Xmobar/Run/Actions.hs b/src/Xmobar/Run/Actions.hs index cbc10c5..fc9682d 100644 --- a/src/Xmobar/Run/Actions.hs +++ b/src/Xmobar/Run/Actions.hs @@ -12,6 +12,7 @@ module Xmobar.Run.Actions ( Button , Action(..) + , isEmpty , runAction , runAction' , stripActions) where @@ -20,12 +21,17 @@ import System.Process (spawnCommand, waitForProcess) import Control.Monad (void) import Text.Regex (Regex, subRegex, mkRegex, matchRegex) import Data.Word (Word32) +import Data.Char (isSpace) type Button = Word32 data Action = Spawn [Button] String deriving (Eq, Read, Show) +isEmpty :: Action -> Bool +isEmpty (Spawn _ s) = all isSpace s + runAction :: Action -> IO () +runAction a | isEmpty a = return () runAction (Spawn _ s) = void $ spawnCommand (s ++ " &") >>= waitForProcess -- | Run action with stdout redirected to stderr diff --git a/src/Xmobar/Run/Exec.hs b/src/Xmobar/Run/Exec.hs index 1879361..e5c5c8c 100644 --- a/src/Xmobar/Run/Exec.hs +++ b/src/Xmobar/Run/Exec.hs @@ -21,6 +21,7 @@ module Xmobar.Run.Exec (Exec (..), tenthSeconds, doEveryTenthSeconds) where import Prelude import Data.Char +import Data.Word (Word32) import Xmobar.Run.Timer (doEveryTenthSeconds, tenthSeconds) import Xmobar.System.Signal @@ -37,3 +38,5 @@ class Show e => Exec e where where go = doEveryTenthSeconds (rate e) $ run e >>= cb trigger :: e -> (Maybe SignalType -> IO ()) -> IO () trigger _ sh = sh Nothing + onClick :: e -> Word32 -> IO () + onClick _ _ = return () diff --git a/src/Xmobar/Run/Loop.hs b/src/Xmobar/Run/Loop.hs index bda41ff..343a857 100644 --- a/src/Xmobar/Run/Loop.hs +++ b/src/Xmobar/Run/Loop.hs @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Run.Loop --- Copyright: (c) 2022 Jose Antonio Ortega Ruiz +-- Copyright: (c) 2022, 2025 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org @@ -28,6 +28,7 @@ import Data.Foldable (for_) import Xmobar.System.Signal import Xmobar.Config.Types +import Xmobar.Config.Template (withEmptyAction) import Xmobar.Run.Runnable (Runnable) import Xmobar.Run.Exec (start, trigger, alias) import Xmobar.Run.Template @@ -53,13 +54,14 @@ refreshLockT var action = do putTMVar var () return r -type LoopFunction = TMVar SignalType -> TVar [String] -> IO () +type LoopFunction = [Runnable] -> TMVar SignalType -> TVar [String] -> IO () loop :: Config -> LoopFunction -> IO () loop conf looper = withDeferSignals $ do cls <- mapM (parseTemplate (commands conf) (sepChar conf)) - (splitTemplate (alignSep conf) (template conf)) + (splitTemplate (alignSep conf) (template conf)) let confSig = unSignalChan (signal conf) + runners = map (\(r, _, _) -> r) (concat cls) sig <- maybe newEmptyTMVarIO pure confSig unless (isJust confSig) $ setupSignalHandler sig refLock <- newRefreshLock @@ -68,7 +70,7 @@ loop conf looper = withDeferSignals $ do cleanupThreads $ \vars -> do tv <- initLoop sig refLock vars - looper sig tv + looper runners sig tv cleanupThreads :: [[([Async ()], a)]] -> IO () cleanupThreads vars = @@ -93,14 +95,15 @@ initLoop sig lock vs = do -- | Runs a command as an independent thread and returns its Async handles -- and the TVar the command will be writing to. startCommand :: TMVar SignalType - -> (Runnable,String,String) + -> (Runnable, String, String) -> IO ([Async ()], TVar String) startCommand sig (com,s,ss) | alias com == "" = do var <- newTVarIO is atomically $ writeTVar var (s ++ ss) return ([], var) | otherwise = do var <- newTVarIO is - let cb str = atomically $ writeTVar var (s ++ str ++ ss) + let cb str = atomically $ + writeTVar var (s ++ withEmptyAction str ++ ss) a1 <- async $ start com cb a2 <- async $ trigger com $ maybe (return ()) (atomically . putTMVar sig) diff --git a/src/Xmobar/Run/Runnable.hs b/src/Xmobar/Run/Runnable.hs index f89f901..a95e70b 100644 --- a/src/Xmobar/Run/Runnable.hs +++ b/src/Xmobar/Run/Runnable.hs @@ -32,6 +32,7 @@ instance Exec Runnable where start (Run a) = start a alias (Run a) = alias a trigger (Run a) = trigger a + onClick (Run a) = onClick a instance Show Runnable where show (Run x) = "Run " ++ show x diff --git a/src/Xmobar/Text/Loop.hs b/src/Xmobar/Text/Loop.hs index 5d2c43f..62dd5c8 100644 --- a/src/Xmobar/Text/Loop.hs +++ b/src/Xmobar/Text/Loop.hs @@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Text.Loop --- Copyright: (c) 2022 Jose Antonio Ortega Ruiz +-- Copyright: (c) 2022, 2025 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org @@ -24,6 +24,7 @@ import Control.Concurrent.STM import Xmobar.System.Signal import Xmobar.Config.Types (Config) import Xmobar.Run.Loop (loop) +import Xmobar.Run.Runnable (Runnable) import Xmobar.Text.Output (initLoop, format) -- | Starts the main event loop and threads @@ -35,12 +36,12 @@ textLoop conf = do loop conf (eventLoop conf) -- | Continuously wait for a signal from a thread or a interrupt handler -eventLoop :: Config -> TMVar SignalType -> TVar [String] -> IO () -eventLoop cfg signal tv = do +eventLoop :: Config -> [Runnable] -> TMVar SignalType -> TVar [String] -> IO () +eventLoop cfg rs signal tv = do typ <- atomically $ takeTMVar signal case typ of - Wakeup -> updateString cfg tv >>= putStrLn >> eventLoop cfg signal tv - _ -> eventLoop cfg signal tv + Wakeup -> updateString cfg tv >>= putStrLn >> eventLoop cfg rs signal tv + _ -> eventLoop cfg rs signal tv updateString :: Config -> TVar [String] -> IO String updateString conf v = do diff --git a/src/Xmobar/X11/Loop.hs b/src/Xmobar/X11/Loop.hs index 2dfb34d..834b1f6 100644 --- a/src/Xmobar/X11/Loop.hs +++ b/src/Xmobar/X11/Loop.hs @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.App.X11EventLoop --- Copyright: (c) 2018, 2020, 2022, 2023, 2024 Jose Antonio Ortega Ruiz +-- Copyright: (c) 2018, 2020, 2022, 2023, 2024, 2025 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org @@ -40,6 +40,8 @@ import qualified Xmobar.Config.Template as CT import qualified Xmobar.Run.Actions as A import qualified Xmobar.Run.Loop as L +import qualified Xmobar.Run.Exec as E +import qualified Xmobar.Run.Runnable as R import qualified Xmobar.System.Utils as U import qualified Xmobar.System.Signal as S @@ -56,6 +58,10 @@ import qualified Xmobar.X11.Window as W import qualified Xmobar.X11.Events as E #endif +data Act = Run R.Runnable | Act [A.Action] deriving Show +type ActPos = (Act, D.Position, D.Position) +type Acts = [ActPos] + runX :: T.XConf -> T.X a -> IO a runX xc f = MR.runReaderT f xc @@ -69,10 +75,14 @@ x11Loop conf = do (r,w) <- W.createWin d fs conf L.loop conf (startLoop (T.XConf d r w (fs :| fl) Map.empty conf)) -startLoop :: T.XConf -> STM.TMVar S.SignalType -> STM.TVar [String] -> IO () -startLoop xcfg sig tv = do +startLoop :: T.XConf + -> [R.Runnable] + -> STM.TMVar S.SignalType + -> STM.TVar [String] + -> IO () +startLoop xcfg runns sig tv = do U.forkThread "X event handler" (eventLoop (T.display xcfg) (T.window xcfg) sig) - signalLoop xcfg [] sig tv + signalLoop xcfg runns [] sig tv -- | Translates X11 events received by w to signals handled by signalLoop eventLoop :: X11.Display -> X11.Window -> STM.TMVar S.SignalType -> IO () @@ -99,17 +109,18 @@ eventLoop dpy w signalv = where (b, p) = (X11x.ev_button ev, fromIntegral $ X11x.ev_x ev) _ -> return () + -- | Continuously wait for a signal from a thread or an interrupt handler. -- The list of actions provides the positions of clickable rectangles, -- and there is a mutable variable for received signals and the list -- of strings updated by running monitors. -signalLoop :: - T.XConf -> D.Actions -> STM.TMVar S.SignalType -> STM.TVar [String] -> IO () -signalLoop xc@(T.XConf d r w fs is cfg) actions signalv strs = do +signalLoop :: T.XConf -> [R.Runnable] -> D.Actions + -> STM.TMVar S.SignalType -> STM.TVar [String] -> IO () +signalLoop xc@(T.XConf d r w fs is cfg) runs actions signalv strs = do typ <- STM.atomically $ STM.takeTMVar signalv case typ of S.Wakeup -> wakeup - S.Action button x -> runActions actions button x >> loopOn + S.Action button x -> runActions runs actions button x >> loopOn S.Reposition -> reposWindow cfg S.ChangeScreen -> updateConfigPosition d cfg >>= reposWindow S.Hide t -> hiderev t S.Hide W.hideWindow @@ -118,7 +129,7 @@ signalLoop xc@(T.XConf d r w fs is cfg) actions signalv strs = do S.TogglePersistent -> updateCfg $ cfg {C.persistent = not $ C.persistent cfg} S.SetAlpha a -> updateCfg $ cfg {C.alpha = a} where - loopOn' xc' = signalLoop xc' actions signalv strs + loopOn' xc' = signalLoop xc' runs actions signalv strs loopOn = loopOn' xc updateCfg cfg' = loopOn' (xc {T.config = cfg'}) @@ -126,7 +137,7 @@ signalLoop xc@(T.XConf d r w fs is cfg) actions signalv strs = do segs <- parseSegments cfg strs xc' <- updateIconCache xc segs actions' <- runX xc' (Draw.draw segs) - signalLoop xc' actions' signalv strs + signalLoop xc' runs actions' signalv strs hiderev t sign op | t == 0 = MR.unless (C.persistent cfg) (op d w) >> loopOn @@ -144,7 +155,7 @@ signalLoop xc@(T.XConf d r w fs is cfg) actions signalv strs = do reposWindow rcfg = do r' <- W.repositionWin d w (NE.head fs) rcfg - signalLoop (T.XConf d r' w fs is rcfg) actions signalv strs + signalLoop (T.XConf d r' w fs is rcfg) runs actions signalv strs parseSegments :: C.Config -> STM.TVar [String] -> IO [[C.Segment]] parseSegments conf v = do @@ -167,10 +178,21 @@ updateConfigPosition disp cfg = else (cfg {C.position = C.OnScreen (n+1) o})) o -> return (cfg {C.position = C.OnScreen 1 o}) -runActions :: D.Actions -> A.Button -> X11.Position -> IO () -runActions actions button pos = - mapM_ A.runAction $ - filter (\(A.Spawn b _) -> button `elem` b) $ - concatMap (\(a,_,_) -> a) $ - filter (\(_, from, to) -> pos' >= from && pos' <= to) actions +toActs :: [R.Runnable] -> D.Actions -> Acts -> Acts +toActs [] _ res = reverse res +toActs _ [] res = reverse res +toActs (r:rs) (([a], x, y):as) res + | A.isEmpty a = toActs rs as ((Run r, x, y):res) +toActs rs ((a, x, y):as) res = toActs rs as ((Act a, x, y):res) + +runAct :: A.Button -> ActPos -> IO () +runAct b (Run r, _, _) = E.onClick r b +runAct b (Act as, _, _) = + mapM_ A.runAction $ filter (\(A.Spawn bs _) -> b `elem` bs) as + +runActions :: [R.Runnable] -> D.Actions -> A.Button -> X11.Position -> IO () +runActions runs actions button pos = + mapM_ (runAct button) $ + filter (\(_, from, to) -> pos' >= from && pos' < to) acts where pos' = fromIntegral pos + acts = toActs runs actions [] |