------------------------------------------------------------------------------ -- | -- Module : Pager -- Copyright : (c) Mads N Noe 2009 -- Maintainer : mntnoe (@) gmail.com -- License : as-is -- -- A pager for DynamicLog showing a symbol for each window on each workspace. -- ------------------------------------------------------------------------------ module Pager ( -- * Usage -- $usage labeledPager ) where -- XMonad modules import XMonad 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 -- My modules import Util -- $usage -- -- The simplest way to use this module is to add something like this in your -- @~\/.xmonad\/xmonad.hs@. Note that you need to patch your xmonad source to -- allow support for user modules (see my @xmonad.hs@). -- -- > import XMonad.Hooks.DynamicLog -- > import Pager -- > -- > main = xmonad $ defaultConfig { -- > ... -- > logHook = myDynamicLog -- > ... -- > } -- > -- > myDynamicLog :: PP -- > myDynamicLog = defaultPP -- > { ppOrder = order -- > , ppExtras = [ labeledPager myDynamicLog windowLabelMap ] -- > } -- > where -- > order (_:l:t:ws:_) = ws:l:t:[] -- > order xs = ["Error in order list: " ++ show xs] -- -- You also need a way to assign symbols to your windows. Here is a simple -- example using single letter symbols, but you also use dzen icons. -- -- > -- | Map windows to symbols for the pager. Symbols for floating windows are in -- > -- lower case. -- > windowLabelMap :: [(String, Query Bool)] -- > windowLabelMap = -- > map whenFloat tiledWindows ++ tiledWindows -- > ++ -- > map whenFloat generalQueries ++ generalQueries -- > where -- > -- > whenFloat (l, q) = (map toLower l, isFloat <&&> q) -- > -- > tiledWindows = -- > [ ("V", className =? "Gvim") -- > , ("E", className =? "Emacs") -- > , ("W", className =? "Firefox") -- > ] -- > -- > generalQueries = -- > [ ("T", appName =? "xterm") -- > , ("X", return True) -- catchall -- > ] -- | The 'DynamicLog' logger to add to 'ppExtras' using the given pretty -- printer and window label map. labeledPager :: PP -> [(String, Query Bool)] -> X (Maybe String) labeledPager pp lm = do s <- gets windowset urgents <- readUrgents sort' <- ppSort pp wl <- queryWindows s lm 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 pp (W.tag ws ++ printWindows wl (W.integrate' $ W.stack ws)) where printer | 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 -- | 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 :: M.Map Window String -- ^ window to symbol map -> [Window] -- ^ windows on the workspace -> String printWindows wl ws = pad $ concat $ map (\w -> fromMaybe "" $ M.lookup w wl) ws where pad "" = "" pad 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, "?") qw ((l, q):lqs) w = runQuery q w >>= if_ (return (w, l)) (qw lqs w)