------------------------------------------------------------------------------ -- | -- Module : Pager -- Copyright : (c) Mads N Noe 2010 -- Maintainer : mail (@) madsnoe.dk -- License : as-is -- -- A pager for DynamicLog showing an for each window on each workspace. -- TODO: Gets slow when there are many windows. Optimize! Not a problem -- for casual use however. -- ------------------------------------------------------------------------------ module Pager ( labeledPager ) where -- XMonad modules import XMonad import Data.Char (toLower) import Data.Maybe ( isJust, fromMaybe ) import qualified Data.Map as M import Data.Map ( (!) ) import Data.List import qualified XMonad.StackSet as W import XMonad.Hooks.DynamicLog import XMonad.Hooks.UrgencyHook -- Custom modules import App import Config import MyApps import Utils -- | The 'DynamicLog' logger to add to 'ppExtras' using the given pretty -- printer and window label map. labeledPager :: PP -> X (Maybe String) labeledPager pp = do s <- gets windowset urgents <- readUrgents sort' <- ppSort pp wl <- queryWindows s windowLabelMap return $ Just $ pprWindowSet' sort' urgents wl pp s -- | like 'pprWindowSet', but append to each workspace the outcome of -- 'printWindows'. pprWindowSet' :: ([W.Workspace String l Window] -> [W.Workspace String l Window]) -- ^ sorting function -> [Window] -- ^ urgent windows -> M.Map Window String -- ^ window to symbol map -> PP -- ^ pretty-Printer -> W.StackSet String l Window sid sd -- ^ stack set -> String pprWindowSet' sort' urgents wl pp s = sepBy (ppWsSep pp) . map fmt . sort' $ map W.workspace (W.current s : W.visible s) ++ W.hidden s where this = W.tag (W.workspace (W.current s)) visibles = map (W.tag . W.workspace) (W.visible s) fmt ws = (printer ws) pp $ print path ws where path | W.tag ws == this = hilightIconPath | W.tag ws == summonWorkspaceTag = grayIconPath | W.tag ws == hiddenWorkspaceTag = grayIconPath | otherwise = iconPath printer ws | W.tag ws == this = ppCurrent | W.tag ws `elem` visibles = ppVisible | any (\x -> maybe False (== W.tag ws) (W.findTag x s)) urgents = \ppC -> ppUrgent ppC . ppHidden ppC | isJust (W.stack ws) = ppHidden | otherwise = ppHiddenNoWindows print path ws = printWindows path wl (W.integrate' $ W.stack ws) -- | Output a list of strings, ignoring empty ones and separating the -- rest with the given separator. sepBy :: String -- ^ separator -> [String] -- ^ fields to output -> String sepBy sep = concat . intersperse sep . filter (not . null) -- | Print a concatenated string of symbols for a list of windows. printWindows :: String -- ^ icon path -> M.Map Window String -- ^ window to symbol map -> [Window] -- ^ windows on the workspace -> String printWindows path wl ws = handleEmpty $ intercalate (icon path "sep.xpm") $ map (\w -> icon path $ fromMaybe defaultIcon (M.lookup w wl)) ws where icon path i = "^i(" ++ path ++ i ++ ")" handleEmpty "" = "^ro(6x6)" handleEmpty xs = xs -- | Query each window in the 'WindowSet' and assign a symbol to it in a map. queryWindows :: WindowSet -> [(String, Query Bool)] -> X (M.Map Window String) queryWindows ws lm = do mapM (qw lm) (W.allWindows ws) >>= return . M.fromList where qw :: [(String, Query Bool)] -> Window -> X (Window, String) qw [] w = return (w, defaultIcon) qw ((l, q):lqs) w = runQuery q w >>= if_ (return (w, l)) (qw lqs w) -- | Map windows to symbols for the pager. Symbols for floating windows are in -- lower case. windowLabelMap :: [(String, Query Bool)] windowLabelMap = map whenFloat windows ++ windows where whenFloat (l, q) = (map toLower l, isFloat <&&> q) windows = zip (map icon apps) (map query apps)