Difference between revisions of "Xmonad/Config archive/Brent Yorgey's darcs xmonad.hs"

From HaskellWiki
Jump to navigation Jump to search
m (fixed my config)
(update to my latest xmonad.hs)
Line 5: Line 5:
 
gnome-volume-manager &
 
gnome-volume-manager &
   
xpmroot ~/images/cherry-tree-wp.png
+
xpmroot ~/images/maine-coast.png
   
 
xmodmap -e 'clear Lock'
 
xmodmap -e 'clear Lock'
Line 11: Line 11:
 
export PATH=$PATH:/home/brent/local/bin
 
export PATH=$PATH:/home/brent/local/bin
 
export OOO_FORCE_DESKTOP=gnome
 
export OOO_FORCE_DESKTOP=gnome
  +
export BROWSER=firefox
gnome-panel &
 
  +
$HOME/local/bin/xmonad | dzen2 -ta r -fg '#a8a3f7' -bg '#3f3c6d'
 
  +
eval `ssh-agent`
  +
xterm -e ssh-add
  +
  +
$HOME/local/bin/xmonad
 
</pre>
 
</pre>
   
Line 22: Line 26:
 
import qualified XMonad.StackSet as W -- (0a) window stack manipulation
 
import qualified XMonad.StackSet as W -- (0a) window stack manipulation
 
import qualified Data.Map as M -- (0b) map creation
 
import qualified Data.Map as M -- (0b) map creation
  +
import Data.List (isPrefixOf, (\\))
  +
import Data.Maybe (isNothing, isJust, catMaybes)
  +
  +
import System.Posix.Unistd
   
 
-- Hooks -----------------------------------------------------
 
-- Hooks -----------------------------------------------------
   
 
import XMonad.Hooks.DynamicLog -- (1) for dzen status bar
 
import XMonad.Hooks.DynamicLog -- (1) for dzen status bar
  +
hiding (pprWindowSet)
 
import XMonad.Hooks.UrgencyHook -- (2) alert me when people use my nick
 
import XMonad.Hooks.UrgencyHook -- (2) alert me when people use my nick
 
-- on IRC
 
-- on IRC
Line 68: Line 77:
 
import XMonad.Actions.UpdatePointer -- (22) auto-warp the pointer to the LR
 
import XMonad.Actions.UpdatePointer -- (22) auto-warp the pointer to the LR
 
-- corner of the focused window
 
-- corner of the focused window
  +
import XMonad.Actions.WithAll
  +
import XMonad.Actions.SpawnOn
  +
  +
import XMonad.Actions.TopicSpace
  +
import XMonad.Actions.DynamicWorkspaces
   
 
-- Prompts ---------------------------------------------------
 
-- Prompts ---------------------------------------------------
Line 74: Line 88:
 
import XMonad.Prompt.Man -- (24) man page prompt
 
import XMonad.Prompt.Man -- (24) man page prompt
 
import XMonad.Prompt.AppendFile -- (25) append stuff to my NOTES file
 
import XMonad.Prompt.AppendFile -- (25) append stuff to my NOTES file
import XMonad.Prompt.Shell -- (26) shell prompt
+
import XMonad.Prompt.Ssh -- (26) ssh prompt
import XMonad.Prompt.Input -- (27) generic input prompt, used for
+
import XMonad.Prompt.Input -- (26) generic input prompt, used for
 
-- making more generic search
 
-- making more generic search
 
-- prompts than those in
 
-- prompts than those in
 
-- XMonad.Prompt.Search
 
-- XMonad.Prompt.Search
  +
import XMonad.Prompt.Workspace
   
 
-- Utilities -------------------------------------------------
 
-- Utilities -------------------------------------------------
Line 85: Line 100:
 
-- status bar
 
-- status bar
 
import XMonad.Util.EZConfig -- (29) "M-C-x" style keybindings
 
import XMonad.Util.EZConfig -- (29) "M-C-x" style keybindings
import XMonad.Util.Scratchpad -- (30) 'scratchpad' terminal
+
import XMonad.Util.NamedScratchpad -- (30) 'scratchpad' terminal
 
import XMonad.Util.Run -- (31) for 'spawnPipe', 'hPutStrLn'
 
import XMonad.Util.Run -- (31) for 'spawnPipe', 'hPutStrLn'
  +
  +
import Control.Monad (when)
   
 
-- (31)
 
-- (31)
 
main = do h <- spawnPipe "dzen2 -ta r -fg '#a8a3f7' -bg '#3f3c6d' -e 'onstart=lower'"
 
main = do h <- spawnPipe "dzen2 -ta r -fg '#a8a3f7' -bg '#3f3c6d' -e 'onstart=lower'"
  +
host <- getHost
xmonad $ byorgeyConfig h -- (0)
 
  +
checkTopicConfig myTopicNames myTopicConfig
  +
xmonad $ byorgeyConfig h host -- (0)
  +
  +
data Host = Desktop | Laptop Bool -- ^ Does the laptop have a Windows key?
  +
deriving (Eq, Read, Show)
  +
  +
getHost :: IO Host
  +
getHost = do
  +
hostName <- nodeName `fmap` getSystemID
  +
return $ case hostName of
  +
"archimedes" -> Laptop True
  +
"euclid" -> Laptop False
  +
"LVN513-12" -> Desktop
  +
_ -> Desktop
  +
  +
myTerminal = "urxvt --perl-lib ~/.urxvt -fg lightgrey -bg black +sb"
  +
myShell = "zsh"
   
byorgeyConfig h = myUrgencyHook $ -- (2)
+
byorgeyConfig h host = myUrgencyHook $ -- (2)
 
defaultConfig
 
defaultConfig
 
{
 
{
 
borderWidth = 2
 
borderWidth = 2
, terminal = "urxvt-custom"
+
, terminal = myTerminal
, workspaces = myWorkspaces
+
, workspaces = myTopicNames
-- , modMask = mod4Mask -- use Windoze key for mod
+
, modMask = if host == Laptop False
  +
then modMask defaultConfig
  +
else mod4Mask
  +
 
, normalBorderColor = "#dddddd"
 
, normalBorderColor = "#dddddd"
 
, focusedBorderColor = "#0033ff"
 
, focusedBorderColor = "#0033ff"
 
-- (22)
 
-- (22)
, logHook = myDynamicLog h >> updatePointer (Relative 1 1)
+
, logHook = myDynamicLog h host
, mouseBindings = myMouseBindings
+
, manageHook = manageSpawn
-- (0)
+
<+> myManageHook
, manageHook = manageHook defaultConfig <+> myManageHook
+
<+> manageHook defaultConfig
 
, layoutHook = myLayoutHook
 
, layoutHook = myLayoutHook
 
, focusFollowsMouse = False
 
, focusFollowsMouse = False
   
 
-- XXX fixme: comment! -- (29)
 
-- XXX fixme: comment! -- (29)
, startupHook = return () >> checkKeymap (byorgeyConfig h) (myKeys h)
+
, startupHook = return () >>
  +
checkKeymap (byorgeyConfig h host)
  +
(myKeys h host)
  +
 
}
 
}
`additionalKeysP` (myKeys h) -- (29)
+
`additionalKeysP` (myKeys h host) -- (29)
  +
  +
checkWS :: (String -> Bool) -> String -> X ()
  +
checkWS p w = do cw <- gets (W.currentTag . windowset)
  +
when (not $ p cw) $ (windows $ W.greedyView w)
   
 
-- have urgent events flash a yellow dzen bar with black text
 
-- have urgent events flash a yellow dzen bar with black text
Line 118: Line 162:
 
{ args = ["-bg", "yellow", "-fg", "black"] }
 
{ args = ["-bg", "yellow", "-fg", "black"] }
   
  +
data TopicItem = TI { topicName :: Topic
-- define some custom workspace tags
 
  +
, topicDir :: Dir
myWorkspaces :: [String]
 
  +
, topicAction :: X ()
myWorkspaces = ["wb", "ir", "c1", "c2", "rf" ]
 
++ ["wr", "dv", "pn", "pl"]
+
}
++ ["0","-","=","[","]","\\"]
 
   
  +
-- define some custom topics for use with the TopicSpace module.
myDynamicLog h = dynamicLogWithPP $ byorgeyPP -- (1)
 
  +
myTopics :: [TopicItem]
{ ppExtras = [ date "%a %b %d %I:%M %p" -- (1,28)
 
  +
myTopics = [ TI "web" "" (spawn "firefox")
  +
, TI "irc" "" (safeRunInTerm "" "ssh lvn")
  +
, TI "mail" "" (safeRunInTerm "" "ssh enx")
  +
, TI "read" "papers" spawnShell
  +
, TI "write" "" spawnShell
  +
, TI "org" "notes"
  +
(spawn "emacs --name org ~/notes/`date +%Y-%m-%d`.org")
  +
, TI "draw" "" (spawn "inkscape")
  +
, TI "xm-conf" ".xmonad"
  +
(edit "~/.xmonad/xmonad.hs" >>
  +
spawnShell)
  +
, TI "xm-hack" "xmonad/XMonadContrib" spawnShell
  +
, TI "em-conf" "" (edit "~/.emacs")
  +
, TI "music" "music" (spawn "rhythmbox")
  +
, TI "net" "" (spawn "wicd-client -n" >>
  +
spawnShell)
  +
, TI "conf" "" spawnShell
  +
, TI "misc" "" spawnShell
  +
, TI "120" "teaching/120/09fa" spawnShell
  +
, TI "ref" "reference" spawnShell
  +
, TI "play" "" spawnShell
  +
, TI "tex-conf" "texmf/tex" (edit "~/texmf/tex/brent.sty")
  +
, TI "mlt" "teaching/mlt" spawnShell
  +
, TI "MR" "writing/Monad.Reader" spawnShell
  +
]
  +
  +
edit :: String -> X ()
  +
edit = spawn . ("em "++)
  +
  +
myTopicNames :: [Topic]
  +
myTopicNames = map topicName myTopics
  +
  +
myTopicConfig :: TopicConfig
  +
myTopicConfig = TopicConfig
  +
{ topicDirs = M.fromList $ map (\(TI n d _) -> (n,d)) myTopics
  +
, defaultTopicAction = const (return ())
  +
, defaultTopic = "web"
  +
, maxTopicHistory = 10
  +
, topicActions = M.fromList $ map (\(TI n _ a) -> (n,a)) myTopics
  +
}
  +
  +
spawnShell :: X ()
  +
spawnShell = currentTopicDir myTopicConfig >>= spawnShellIn
  +
  +
spawnShellIn :: Dir -> X ()
  +
spawnShellIn dir = spawn $ myTerminal ++ " -title urxvt -e sh -c 'cd ''" ++ dir ++ "'' && " ++ myShell ++ "'"
  +
  +
goto :: Topic -> X ()
  +
goto = switchTopic myTopicConfig
  +
  +
promptedGoto :: X ()
  +
promptedGoto = workspacePrompt myXPConfig goto
  +
  +
promptedGotoOtherScreen :: X ()
  +
promptedGotoOtherScreen =
  +
workspacePrompt myXPConfig $ \ws -> do
  +
nextScreen
  +
goto ws
  +
  +
promptedShift :: X ()
  +
promptedShift = workspacePrompt myXPConfig $ windows . W.shift
  +
  +
-- XXX offset scratchpad windows by a bit --- each one different?
  +
scratchpadSize = W.RationalRect (1/4) (1/4) (1/2) (1/2)
  +
mySPFloat = customFloating scratchpadSize
  +
  +
scratchpads =
  +
[ NS "term" "urxvt-custom -title term" (title =? "term") mySPFloat
  +
, NS "ghci" "urxvt-custom -e ghci" (title =? "ghci") mySPFloat
  +
, NS "sync" "urxvt-custom -e sy" (title =? "sy") mySPFloat
  +
, NS "top" "urxvt-custom -e htop" (title =? "htop") mySPFloat
  +
]
  +
  +
myDynamicLog h host = dynamicLogWithPP $ byorgeyPP -- (1)
  +
{ ppVisible = dzenColor "blue" "#a8a3f7" . pad
  +
, ppExtras = [ date "%a %b %d %I:%M %p" -- (1,28)
 
, loadAvg -- (28)
 
, loadAvg -- (28)
, battery
 
 
]
 
]
, ppOrder = \(ws:l:t:exs) -> [t,l,ws]++exs -- (1)
+
++ (case host of Laptop _ -> [battery]
  +
_ -> [])
  +
, ppOrder = \(ws:l:t:exs) -> [t,l,ws]++exs -- (1)
 
, ppOutput = hPutStrLn h -- (1,31)
 
, ppOutput = hPutStrLn h -- (1,31)
, ppTitle = shorten 45
+
, ppTitle = shorten (case host of Laptop _ -> 45
  +
Desktop -> 60)
  +
, ppSort = fmap (namedScratchpadFilterOutWorkspace.) (ppSort byorgeyPP)
  +
, ppHiddenNoWindows = const ""
 
}
 
}
 
-- my custom mouse bindings.
 
myMouseBindings (XConfig {modMask = modm}) = M.fromList $ -- (0b)
 
-- these two are normal...
 
[ ((modm, button1), (\w -> focus w >> mouseMoveWindow w)) -- (0)
 
, ((modm, button2), (\w -> focus w >> windows W.swapMaster)) -- (0)
 
-- but this one uses the FlexibleManipulate extension. -- (17)
 
, ((modm, button3), (\w -> focus w >> Flex.mouseWindow Flex.linear w)) ]
 
   
 
-- my custom keybindings.
 
-- my custom keybindings.
myKeys h = myKeymap (byorgeyConfig h)
+
myKeys h host = myKeymap host (byorgeyConfig h host)
   
myKeymap conf =
+
myKeymap host conf =
   
-- mod-[1..9] %! Switch to workspace N
+
-- mod-[1..], Switch to workspace N
-- mod-shift-[1..9] %! Move client to workspace N
+
-- mod-shift-[1..], Move client to workspace N
  +
-- mod-ctrl-[1..], Switch to workspace N on other screen
[ (m ++ "M-" ++ [k], windows $ f i) -- (0)
 
  +
[ (m ++ "M-" ++ [k], f i) -- (0)
 
| (i, k) <- zip (XMonad.workspaces conf) "1234567890-=[]\\" -- (0)
 
| (i, k) <- zip (XMonad.workspaces conf) "1234567890-=[]\\" -- (0)
, (f, m) <- [(W.greedyView, ""), (W.shift, "S-")] -- (0a)
+
, (f, m) <- [ (windows . W.view, "") -- (0a)
  +
, (windows . W.shift, "S-")
  +
, (\ws -> nextScreen >> (windows . W.view $ ws), "C-")
  +
]
 
]
 
]
   
 
++
 
++
[ ("M-S-x", spawn $ terminal conf) -- (0)
+
[ ("M-S-x", spawnShell) -- (0)
 
, ("M-S-b", spawn "urxvt-big")
 
, ("M-S-b", spawn "urxvt-big")
  +
, ("M-g", promptedGoto)
  +
, ("M-C-g", promptedGotoOtherScreen)
  +
, ("M-S-g", promptedShift)
  +
, ("M-S-C-g", workspacePrompt myXPConfig $ withAll' . W.shiftWin)
   
 
-- in conjunction with manageHook, open a small temporary
 
-- in conjunction with manageHook, open a small temporary
 
-- floating terminal
 
-- floating terminal
, ("M-x s", scratchpadSpawnAction conf) -- (30)
+
, ("M-a s", namedScratchpadAction scratchpads "term") -- (30)
  +
, ("M-a g", namedScratchpadAction scratchpads "ghci")
 
  +
, ("M-a t", namedScratchpadAction scratchpads "top")
, ("M-S-a", kill) -- (0)
 
  +
]
  +
++ (case host of Laptop _ ->
  +
[("M-a y", namedScratchpadAction scratchpads "sync")]
  +
_ -> []
  +
)
  +
++
  +
[ ("M-S-a", kill) -- (0)
  +
, ("M-S-C-a", killAll)
   
 
-- some gap-toggling
 
-- some gap-toggling
, ("M-g b", sendMessage $ ToggleStrut D) -- (3)
+
, ("M-C-p b", sendMessage $ ToggleStrut D) -- (3)
, ("M-g t", sendMessage $ ToggleStrut U) -- "
+
, ("M-C-p t", sendMessage $ ToggleStrut U) -- "
, ("M-g a", sendMessage $ ToggleStruts) -- "
+
, ("M-C-p a", sendMessage $ ToggleStruts) -- "
   
, ("M-g g", sendMessage $ ToggleGaps)
+
, ("M-C-p g", sendMessage $ ToggleGaps)
 
]
 
]
   
 
++
 
++
[ ("M-g " ++ f ++ " <" ++ dk ++ ">", sendMessage $ m d)
+
[ ("M-C-p " ++ f ++ " <" ++ dk ++ ">", sendMessage $ m d)
 
| (dk, d) <- [("L",L), ("D",D), ("U",U), ("R",R)]
 
| (dk, d) <- [("L",L), ("D",D), ("U",U), ("R",R)]
 
, (f, m) <- [("v", ToggleGap), ("h", IncGap 10), ("f", DecGap 10)]
 
, (f, m) <- [("v", ToggleGap), ("h", IncGap 10), ("f", DecGap 10)]
Line 186: Line 317:
 
, ("M-S-C-<R>", shiftToNext >> nextWS ) -- "
 
, ("M-S-C-<R>", shiftToNext >> nextWS ) -- "
 
, ("M-S-C-<L>", shiftToPrev >> prevWS ) -- "
 
, ("M-S-C-<L>", shiftToPrev >> prevWS ) -- "
, ("M-<R>", moveTo Next NonEmptyWS) -- "
+
, ("M-<R>", moveTo Next HiddenNonEmptyWS) -- "
, ("M-<L>", moveTo Prev NonEmptyWS) -- "
+
, ("M-<L>", moveTo Prev HiddenNonEmptyWS) -- "
, ("M-f", moveTo Next EmptyWS) -- "
+
, ("M-f", newCodeWS) -- "
, ("M-d", moveTo Prev EmptyWS) -- "
 
   
 
-- expand/shrink windows
 
-- expand/shrink windows
Line 199: Line 329:
 
-- switch to previous workspace
 
-- switch to previous workspace
 
, ("M-z", toggleWS) -- (16)
 
, ("M-z", toggleWS) -- (16)
  +
, ("M-S-z", killAll >> moveTo Prev HiddenNonEmptyWS)
-- , ("M-a", cycleRecentWS [xK_Super_L] xK_a xK_s) -- this seems to be broken on this laptop
 
   
  +
-- dynamic workspace bindings
-- lock the screen with xscreensaver
 
  +
, ("M-n", addWorkspacePrompt myXPConfig)
  +
, ("M-C-r", removeWorkspace)
  +
, ("M-C-S-r", killAll >> removeWorkspace)
  +
  +
-- move between screens
  +
, ("M-s", nextScreen)
  +
, ("M-w", swapNextScreen)
  +
, ("M-e", shiftNextScreen)
  +
  +
-- lock the screen with xscreensaver
 
, ("M-S-l", spawn "xscreensaver-command -lock") -- (0)
 
, ("M-S-l", spawn "xscreensaver-command -lock") -- (0)
   
 
-- bainsh the pointer
 
-- bainsh the pointer
, ("M-b", warpToWindow 1 1) -- (18)
+
, ("M-'", banishScreen LowerRight) -- (18)
  +
, ("M-b", warpToWindow (1/2) (1/2))
   
 
-- some programs to start with keybindings.
 
-- some programs to start with keybindings.
, ("M-x f", runOrRaise "firefox-3.0" (className =? "Firefox-bin")) -- (21)
+
, ("M-x f", spawnOn "web" "firefox")
, ("M-x g", spawn "gimp") -- (0)
+
, ("M-x o", spawnOn "web" "opera")
  +
, ("M-x g", spawnOn "draw" "gimp") -- (0)
 
, ("M-x m", spawn "rhythmbox") -- (0)
 
, ("M-x m", spawn "rhythmbox") -- (0)
 
, ("M-x t", spawn "xclock -update 1") -- (0)
 
, ("M-x t", spawn "xclock -update 1") -- (0)
 
, ("M-x S-g", spawn "javaws ~/playing/go/cgoban.jnlp") -- (0)
 
, ("M-x S-g", spawn "javaws ~/playing/go/cgoban.jnlp") -- (0)
  +
, ("M-x n", goto "org")
   
 
-- configuration.
 
-- configuration.
, ("M-c x", spawn "em ~/.xmonad/xmonad.hs") -- (0)
+
, ("M-c x", goto "xm-conf")
, ("M-c n", spawn "network-admin" >> spawn (terminal conf ++ " -e 'watch ifconfig'"))
+
, ("M-c e", goto "em-conf")
, ("M-c v", spawn "gnome-volume-control --class=Volume") -- (0)
+
, ("M-c t", goto "tex-conf")
  +
] ++
  +
(case host of Laptop _ -> [("M-c n", goto "net")]
  +
_ -> [])
  +
++
  +
[ ("M-c v", spawn "urxvt -e alsamixer") -- (0)
 
, ("M-c k", spawn "xkill")
 
, ("M-c k", spawn "xkill")
  +
, ("M-c M-S-a", killAll)
   
 
-- window navigation keybindings.
 
-- window navigation keybindings.
Line 231: Line 380:
   
 
-- switch to urgent window
 
-- switch to urgent window
, ("M-s", focusUrgent)
+
, ("M-u", focusUrgent)
   
 
-- toggles: fullscreen, flip x, flip y, mirror, no borders
 
-- toggles: fullscreen, flip x, flip y, mirror, no borders
Line 246: Line 395:
 
, ("M-p m", manPrompt myXPConfig) -- (24)
 
, ("M-p m", manPrompt myXPConfig) -- (24)
 
-- add single lines to my NOTES file from a prompt. -- (25)
 
-- add single lines to my NOTES file from a prompt. -- (25)
, ("M-p n", appendFilePrompt myXPConfig "/home/brent/misc/NOTES")
+
, ("M-p n", appendFilePrompt myXPConfig "$HOME/NOTES")
, ("M-p x", appendFilePrompt myXPConfig "/home/brent/foo/BLAH")
 
 
-- shell prompt.
 
-- shell prompt.
, ("M-p s", shellPrompt myXPConfig) -- (26)
+
, ("M-p s", sshPrompt myXPConfig) -- (26)
, ("M-p p", spawn "exe=`dmenu_path | dmenu` && eval \"exec $exe\"") -- (0)
 
   
 
-- some searches.
 
-- some searches.
Line 258: Line 405:
 
-- some random utilities.
 
-- some random utilities.
 
, ("M-C-c", spawn "dzen-cal") -- calendar
 
, ("M-C-c", spawn "dzen-cal") -- calendar
  +
, ("<Print>", spawn "scrot")
 
  +
, ("C-<Print>", spawn "sleep 0.2; scrot -s")
-- todos. -- (25)
 
, ("M-C-t a", appendFilePrompt myXPConfig "/home/brent/misc/TODO")
 
, ("M-C-t l", spawn "dzen-show-todos") -- (0)
 
, ("M-C-t e", spawn "emacs ~/misc/TODO") -- (0)
 
, ("M-C-t u", spawn "cp ~/misc/TODO.backup ~/misc/TODO ; dzen-show-todos") ]
 
++ -- (0)
 
[ ("M-C-t " ++ [key], spawn ("del-todo " ++ show n ++ " ; dzen-show-todos"))
 
| (key, n) <- zip "1234567890" [1..10]
 
 
]
 
]
  +
  +
newCodeWS :: X ()
  +
newCodeWS = withWindowSet $ \w -> do
  +
let wss = W.workspaces w
  +
cws = map W.tag $ filter (\ws -> "code" `isPrefixOf` W.tag ws && isJust (W.stack ws)) wss
  +
num = head $ [0..] \\ catMaybes (map (readMaybe . drop 4) cws)
  +
new = "code" ++ show num
  +
when (not $ new `elem` (map W.tag wss)) $ addWorkspace new
  +
windows $ W.view new
  +
where readMaybe s = case reads s of
  +
[(r,_)] -> Just r
  +
_ -> Nothing
   
 
-- Perform a search, using the given method, based on a keypress
 
-- Perform a search, using the given method, based on a keypress
Line 279: Line 431:
 
, ((0, xK_p), method maps) -- "
 
, ((0, xK_p), method maps) -- "
 
, ((0, xK_d), method dictionary) -- "
 
, ((0, xK_d), method dictionary) -- "
  +
, ((0, xK_a), method alpha) -- "
  +
, ((0, xK_l), method lucky) -- "
  +
, ((0, xK_i), method images)
 
]
 
]
   
Line 292: Line 447:
   
 
-- Switch to the "web" workspace
 
-- Switch to the "web" workspace
viewWeb = windows (W.greedyView "wb") -- (0,0a)
+
viewWeb = windows (W.view "web") -- (0,0a)
   
 
-- some nice colors for the prompt windows to match the dzen status bar.
 
-- some nice colors for the prompt windows to match the dzen status bar.
Line 307: Line 462:
 
[ className =? c --> doCenterFloat | c <- myFloats ] -- (4)
 
[ className =? c --> doCenterFloat | c <- myFloats ] -- (4)
 
++
 
++
[ title =? t --> doFloat | t <- myFloatTitles ]
+
[ fmap (t `isPrefixOf`) title --> doFloat | t <- myFloatTitles ]
 
++
 
++
 
-- send certain windows to certain workspaces
 
-- send certain windows to certain workspaces
[ className =? "Rhythmbox" --> doF (W.shift "-") -- (0,0a)
+
[ className =? "Rhythmbox" --> doF (W.shift "music") -- (0,0a)
, className =? "XDvi" --> doF (W.shift "dv") -- (0,0a)
 
 
-- unmanage docks such as gnome-panel and dzen
 
-- unmanage docks such as gnome-panel and dzen
 
, manageDocks -- (3)
 
, manageDocks -- (3)
 
-- manage the scratchpad terminal window
 
-- manage the scratchpad terminal window
, scratchpadManageHookDefault -- (30)
+
, namedScratchpadManageHook scratchpads -- (30)
  +
, appName =? "xbuffy-main" --> doFloatAt 0.92 0.66
  +
, appName =? "xbuffy-aux" --> doFloatAt 0.92 0.81
 
]
 
]
 
-- windows to auto-float
 
-- windows to auto-float
Line 323: Line 479:
 
, "Xmessage"
 
, "Xmessage"
 
, "gnome-search-tool"
 
, "gnome-search-tool"
  +
, "Qjackctl.bin"
  +
, "Icfp"
  +
, "Floating"
  +
, "Game"
 
]
 
]
myFloatTitles = ["Bridge Bid", "xbuffy"]
+
myFloatTitles = ["Bridge Bid", "Pong", "Floating"]
   
 
-- specify a custom layout hook.
 
-- specify a custom layout hook.
Line 338: Line 498:
 
-- to switch to a new working dir. -- (10,11)
 
-- to switch to a new working dir. -- (10,11)
 
workspaceDir "~" $
 
workspaceDir "~" $
 
-- modWorkspace "plan" (workspaceDir "~/org") $
 
-- modWorkspace "=" (workspaceDir "~/xmonad") $
 
   
 
-- navigate directionally rather than with mod-j/k
 
-- navigate directionally rather than with mod-j/k
Line 350: Line 507:
 
mkToggle1 REFLECTX $ -- (14,13)
 
mkToggle1 REFLECTX $ -- (14,13)
 
mkToggle1 REFLECTY $ -- (14,13)
 
mkToggle1 REFLECTY $ -- (14,13)
-- mkToggle1 NOBORDERS $ -- "
+
mkToggle1 NOBORDERS $ -- "
 
mkToggle1 MIRROR $ -- "
 
mkToggle1 MIRROR $ -- "
   
Line 357: Line 514:
   
 
-- "web" and "irc" start in Full mode and can switch to tiled...
 
-- "web" and "irc" start in Full mode and can switch to tiled...
onWorkspaces ["wb","ir"] (Full ||| myTiled) $ -- (10,0)
+
onWorkspaces ["web","irc"] (Full ||| myTiled) $ -- (10,0)
   
 
-- ...whereas all other workspaces start tall and can switch
 
-- ...whereas all other workspaces start tall and can switch
Line 368: Line 525:
 
myTiled = named "Tall" $ ResizableTall 1 0.03 0.5 [] -- (9,5)
 
myTiled = named "Tall" $ ResizableTall 1 0.03 0.5 [] -- (9,5)
 
</haskell>
 
</haskell>
 
For other support scripts etc., see [[Xmonad/Config archive/Brent Yorgey's xmonad.hs|my 0.6 config]].
 

Revision as of 18:18, 6 December 2009

My .xsession file:

gnome-power-manager 
gnome-volume-manager &

xpmroot ~/images/maine-coast.png

xmodmap -e 'clear Lock'

export PATH=$PATH:/home/brent/local/bin
export OOO_FORCE_DESKTOP=gnome
export BROWSER=firefox

eval `ssh-agent`
xterm -e ssh-add

$HOME/local/bin/xmonad

My current config file, which works with the latest development xmonad and xmonad-contrib, annotated to show which extensions are being used where:

import XMonad                          -- (0) core xmonad libraries

import qualified XMonad.StackSet as W  -- (0a) window stack manipulation
import qualified Data.Map as M         -- (0b) map creation
import Data.List (isPrefixOf, (\\))
import Data.Maybe (isNothing, isJust, catMaybes)

import System.Posix.Unistd

-- Hooks -----------------------------------------------------

import XMonad.Hooks.DynamicLog     -- (1)  for dzen status bar
  hiding (pprWindowSet)
import XMonad.Hooks.UrgencyHook    -- (2)  alert me when people use my nick
                                   --      on IRC
import XMonad.Hooks.ManageDocks    -- (3)  automatically avoid covering my
                                   --      status bar with windows
import XMonad.Hooks.ManageHelpers  -- (4)  for doCenterFloat, put floating
                                   --      windows in the middle of the
                                   --      screen

-- Layout ----------------------------------------------------

import XMonad.Layout.ResizableTile -- (5)  resize non-master windows too
import XMonad.Layout.Grid          -- (6)  grid layout
import XMonad.Layout.TwoPane
import XMonad.Layout.NoBorders     -- (7)  get rid of borders sometimes
                                   -- (8)  navigate between windows
import XMonad.Layout.WindowNavigation  --  directionally
import XMonad.Layout.Named         -- (9)  rename some layouts
import XMonad.Layout.PerWorkspace  -- (10) use different layouts on different WSs
import XMonad.Layout.WorkspaceDir  -- (11) set working directory
                                   --      per-workspace
import XMonad.Layout.Reflect       -- (13) ability to reflect layouts
import XMonad.Layout.MultiToggle   -- (14) apply layout modifiers dynamically
import XMonad.Layout.MultiToggle.Instances
                                   -- (15) ability to magnify the focused
                                   --      window
import qualified XMonad.Layout.Magnifier as Mag

import XMonad.Layout.Gaps

-- Actions ---------------------------------------------------

import XMonad.Actions.CycleWS      -- (16) general workspace-switching
                                   --      goodness
import XMonad.Actions.CycleRecentWS
                                   -- (17) more flexible window resizing
import qualified XMonad.Actions.FlexibleManipulate as Flex
import XMonad.Actions.Warp         -- (18) warp the mouse pointer
import XMonad.Actions.Submap       -- (19) create keybinding submaps
import XMonad.Actions.Search       -- (20) some predefined web searches
import XMonad.Actions.WindowGo     -- (21) runOrRaise
import XMonad.Actions.UpdatePointer -- (22) auto-warp the pointer to the LR
                                    --      corner of the focused window
import XMonad.Actions.WithAll
import XMonad.Actions.SpawnOn

import XMonad.Actions.TopicSpace
import XMonad.Actions.DynamicWorkspaces

-- Prompts ---------------------------------------------------

import XMonad.Prompt                -- (23) general prompt stuff.
import XMonad.Prompt.Man            -- (24) man page prompt
import XMonad.Prompt.AppendFile     -- (25) append stuff to my NOTES file
import XMonad.Prompt.Ssh            -- (26) ssh prompt
import XMonad.Prompt.Input          -- (26) generic input prompt, used for
                                    --      making more generic search
                                    --      prompts than those in
                                    --      XMonad.Prompt.Search
import XMonad.Prompt.Workspace

-- Utilities -------------------------------------------------

import XMonad.Util.Loggers          -- (28) some extra loggers for my
                                    --      status bar
import XMonad.Util.EZConfig         -- (29) "M-C-x" style keybindings
import XMonad.Util.NamedScratchpad  -- (30) 'scratchpad' terminal
import XMonad.Util.Run              -- (31) for 'spawnPipe', 'hPutStrLn'

import Control.Monad (when)

                                                                -- (31)
main = do h <- spawnPipe "dzen2 -ta r -fg '#a8a3f7' -bg '#3f3c6d' -e 'onstart=lower'"
          host <- getHost
          checkTopicConfig myTopicNames myTopicConfig
          xmonad $ byorgeyConfig h host                         -- (0)

data Host = Desktop | Laptop Bool -- ^ Does the laptop have a Windows key?
  deriving (Eq, Read, Show)

getHost :: IO Host
getHost = do
  hostName <- nodeName `fmap` getSystemID
  return $ case hostName of
    "archimedes" -> Laptop True
    "euclid"     -> Laptop False
    "LVN513-12"  -> Desktop
    _            -> Desktop

myTerminal = "urxvt --perl-lib ~/.urxvt -fg lightgrey -bg black +sb"
myShell = "zsh"

byorgeyConfig h host = myUrgencyHook $                         -- (2)
     defaultConfig
       {
         borderWidth        = 2
       , terminal           = myTerminal
       , workspaces         = myTopicNames
       , modMask            = if host == Laptop False
                                then modMask defaultConfig
                                else mod4Mask

       , normalBorderColor  = "#dddddd"
       , focusedBorderColor = "#0033ff"
                                                                -- (22)
       , logHook            = myDynamicLog h host
       , manageHook         = manageSpawn
                              <+> myManageHook
                              <+> manageHook defaultConfig
       , layoutHook         = myLayoutHook
       , focusFollowsMouse  = False

         -- XXX fixme: comment!                                 -- (29)
       , startupHook        = return () >>
                              checkKeymap (byorgeyConfig h host)
                                          (myKeys h host)

       }
       `additionalKeysP` (myKeys h host)                        -- (29)

checkWS :: (String -> Bool) -> String -> X ()
checkWS p w = do cw <- gets (W.currentTag . windowset)
                 when (not $ p cw) $ (windows $ W.greedyView w)

-- have urgent events flash a yellow dzen bar with black text
myUrgencyHook = withUrgencyHook dzenUrgencyHook                 -- (2)
    { args = ["-bg", "yellow", "-fg", "black"] }

data TopicItem = TI { topicName :: Topic
                    , topicDir  :: Dir
                    , topicAction :: X ()
                    }

-- define some custom topics for use with the TopicSpace module.
myTopics :: [TopicItem]
myTopics = [ TI "web" "" (spawn "firefox")
           , TI "irc" "" (safeRunInTerm "" "ssh lvn")
           , TI "mail" "" (safeRunInTerm "" "ssh enx")
           , TI "read" "papers" spawnShell
           , TI "write" "" spawnShell
           , TI "org" "notes"
              (spawn "emacs --name org ~/notes/`date +%Y-%m-%d`.org")
           , TI "draw" "" (spawn "inkscape")
           , TI "xm-conf" ".xmonad"
              (edit "~/.xmonad/xmonad.hs" >>
               spawnShell)
           , TI "xm-hack" "xmonad/XMonadContrib" spawnShell
           , TI "em-conf" "" (edit "~/.emacs")
           , TI "music" "music" (spawn "rhythmbox")
           , TI "net" "" (spawn "wicd-client -n" >>
                          spawnShell)
           , TI "conf" "" spawnShell
           , TI "misc" "" spawnShell
           , TI "120" "teaching/120/09fa" spawnShell
           , TI "ref" "reference" spawnShell
           , TI "play" "" spawnShell
           , TI "tex-conf" "texmf/tex" (edit "~/texmf/tex/brent.sty")
           , TI "mlt" "teaching/mlt" spawnShell
           , TI "MR" "writing/Monad.Reader" spawnShell
           ]

edit :: String -> X ()
edit = spawn . ("em "++)

myTopicNames :: [Topic]
myTopicNames = map topicName myTopics

myTopicConfig :: TopicConfig
myTopicConfig = TopicConfig
  { topicDirs = M.fromList $ map (\(TI n d _) -> (n,d)) myTopics
  , defaultTopicAction = const (return ())
  , defaultTopic = "web"
  , maxTopicHistory = 10
  , topicActions = M.fromList $ map (\(TI n _ a) -> (n,a)) myTopics
  }

spawnShell :: X ()
spawnShell = currentTopicDir myTopicConfig >>= spawnShellIn

spawnShellIn :: Dir -> X ()
spawnShellIn dir = spawn $ myTerminal ++ " -title urxvt -e sh -c 'cd ''" ++ dir ++ "'' && " ++ myShell ++ "'"

goto :: Topic -> X ()
goto = switchTopic myTopicConfig

promptedGoto :: X ()
promptedGoto = workspacePrompt myXPConfig goto

promptedGotoOtherScreen :: X ()
promptedGotoOtherScreen =
  workspacePrompt myXPConfig $ \ws -> do
    nextScreen
    goto ws

promptedShift :: X ()
promptedShift = workspacePrompt myXPConfig $ windows . W.shift

-- XXX offset scratchpad windows by a bit --- each one different?
scratchpadSize = W.RationalRect (1/4) (1/4) (1/2) (1/2)
mySPFloat = customFloating scratchpadSize

scratchpads =
  [ NS "term" "urxvt-custom -title term" (title =? "term") mySPFloat
  , NS "ghci" "urxvt-custom -e ghci" (title =? "ghci") mySPFloat
  , NS "sync" "urxvt-custom -e sy" (title =? "sy") mySPFloat
  , NS "top"  "urxvt-custom -e htop" (title =? "htop") mySPFloat
  ]

myDynamicLog h host = dynamicLogWithPP $ byorgeyPP              -- (1)
  { ppVisible = dzenColor "blue" "#a8a3f7" . pad
  , ppExtras = [ date "%a %b %d  %I:%M %p"                      -- (1,28)
               , loadAvg                                        -- (28)
               ]
               ++ (case host of Laptop _ -> [battery]
                                _      -> [])
  , ppOrder  = \(ws:l:t:exs) -> [t,l,ws]++exs                   -- (1)
  , ppOutput = hPutStrLn h                                      -- (1,31)
  , ppTitle  = shorten (case host of Laptop _ -> 45
                                     Desktop  -> 60)
  , ppSort   = fmap (namedScratchpadFilterOutWorkspace.) (ppSort byorgeyPP)
  , ppHiddenNoWindows = const ""
  }

-- my custom keybindings.
myKeys h host = myKeymap host (byorgeyConfig h host)

myKeymap host conf =

    -- mod-[1..],       Switch to workspace N
    -- mod-shift-[1..], Move client to workspace N
    -- mod-ctrl-[1..],  Switch to workspace N on other screen
    [ (m ++ "M-" ++ [k], f i)                                   -- (0)
        | (i, k) <- zip (XMonad.workspaces conf) "1234567890-=[]\\" -- (0)
        , (f, m) <- [ (windows . W.view, "")                    -- (0a)
                    , (windows . W.shift, "S-")
                    , (\ws -> nextScreen >> (windows . W.view $ ws), "C-")
                    ]
    ]

    ++
    [ ("M-S-x", spawnShell)                          -- (0)
    , ("M-S-b", spawn "urxvt-big")
    , ("M-g",   promptedGoto)
    , ("M-C-g", promptedGotoOtherScreen)
    , ("M-S-g", promptedShift)
    , ("M-S-C-g", workspacePrompt myXPConfig $ withAll' . W.shiftWin)

      -- in conjunction with manageHook, open a small temporary
      -- floating terminal
    , ("M-a s", namedScratchpadAction scratchpads "term")       -- (30)
    , ("M-a g", namedScratchpadAction scratchpads "ghci")
    , ("M-a t", namedScratchpadAction scratchpads "top")
    ]
    ++ (case host of Laptop _ ->
                       [("M-a y", namedScratchpadAction scratchpads "sync")]
                     _ -> []
       )
    ++
    [ ("M-S-a", kill)                                           -- (0)
    , ("M-S-C-a", killAll)

    -- some gap-toggling
    , ("M-C-p b", sendMessage $ ToggleStrut D)                    -- (3)
    , ("M-C-p t", sendMessage $ ToggleStrut U)                    --  "
    , ("M-C-p a", sendMessage $ ToggleStruts)                     --  "

    , ("M-C-p g", sendMessage $ ToggleGaps)
    ]

    ++
    [ ("M-C-p " ++ f ++ " <" ++ dk ++ ">", sendMessage $ m d)
        | (dk, d) <- [("L",L), ("D",D), ("U",U), ("R",R)]
        , (f, m)  <- [("v", ToggleGap), ("h", IncGap 10), ("f", DecGap 10)]
    ]

    ++
    -- rotate workspaces.
    [ ("M-C-<R>",   nextWS )                                    -- (16)
    , ("M-C-<L>",   prevWS )                                    --  "
    , ("M-S-<R>",   shiftToNext )                               --  "
    , ("M-S-<L>",   shiftToPrev )                               --  "
    , ("M-S-C-<R>", shiftToNext >> nextWS )                     --  "
    , ("M-S-C-<L>", shiftToPrev >> prevWS )                     --  "
    , ("M-<R>",     moveTo Next HiddenNonEmptyWS)               --  "
    , ("M-<L>",     moveTo Prev HiddenNonEmptyWS)               --  "
    , ("M-f",       newCodeWS)                                  --  "

    -- expand/shrink windows
    , ("M-r k", sendMessage MirrorExpand)                       -- (5)
    , ("M-r j", sendMessage MirrorShrink)                       -- (5)
    , ("M-r h", sendMessage Shrink)                             -- (0)
    , ("M-r l", sendMessage Expand)                             -- (0)

    -- switch to previous workspace
    , ("M-z", toggleWS)                                         -- (16)
    , ("M-S-z", killAll >> moveTo Prev HiddenNonEmptyWS)

    -- dynamic workspace bindings
    , ("M-n", addWorkspacePrompt myXPConfig)
    , ("M-C-r", removeWorkspace)
    , ("M-C-S-r", killAll >> removeWorkspace)

    -- move between screens
    , ("M-s", nextScreen)
    , ("M-w", swapNextScreen)
    , ("M-e", shiftNextScreen)

      -- lock the screen with xscreensaver
    , ("M-S-l", spawn "xscreensaver-command -lock")             -- (0)

    -- bainsh the pointer
    , ("M-'", banishScreen LowerRight)                          -- (18)
    , ("M-b", warpToWindow (1/2) (1/2))

    -- some programs to start with keybindings.
    , ("M-x f", spawnOn "web" "firefox")
    , ("M-x o", spawnOn "web" "opera")
    , ("M-x g", spawnOn "draw" "gimp")                          -- (0)
    , ("M-x m", spawn "rhythmbox")                              -- (0)
    , ("M-x t", spawn "xclock -update 1")                       -- (0)
    , ("M-x S-g", spawn "javaws ~/playing/go/cgoban.jnlp")      -- (0)
    , ("M-x n", goto "org")

    -- configuration.
    , ("M-c x", goto "xm-conf")
    , ("M-c e", goto "em-conf")
    , ("M-c t", goto "tex-conf")
    ] ++
    (case host of Laptop _ -> [("M-c n", goto "net")]
                  _        -> [])
    ++
    [ ("M-c v", spawn "urxvt -e alsamixer")                     -- (0)
    , ("M-c k", spawn "xkill")
    , ("M-c M-S-a", killAll)

    -- window navigation keybindings.
    , ("C-<R>", sendMessage $ Go R)                             -- (8)
    , ("C-<L>", sendMessage $ Go L)                             --  "
    , ("C-<U>", sendMessage $ Go U)                             --  "
    , ("C-<D>", sendMessage $ Go D)                             --  "
    , ("S-C-<R>", sendMessage $ Swap R)                         --  "
    , ("S-C-<L>", sendMessage $ Swap L)                         --  "
    , ("S-C-<U>", sendMessage $ Swap U)                         --  "
    , ("S-C-<D>", sendMessage $ Swap D)                         --  "

    -- switch to urgent window
    , ("M-u", focusUrgent)

    -- toggles: fullscreen, flip x, flip y, mirror, no borders
    , ("M-C-<Space>", sendMessage $ Toggle NBFULL)              -- (14)
    , ("M-C-x",       sendMessage $ Toggle REFLECTX)            -- (14,13)
    , ("M-C-y",       sendMessage $ Toggle REFLECTY)            -- (14,13)
    , ("M-C-m",       sendMessage $ Toggle MIRROR)              --  "
    , ("M-C-b",       sendMessage $ Toggle NOBORDERS)           --  "

    -- some prompts.
      -- ability to change the working dir for a workspace.
    , ("M-p d", changeDir myXPConfig)                           -- (11)
      -- man page prompt
    , ("M-p m", manPrompt myXPConfig)                           -- (24)
      -- add single lines to my NOTES file from a prompt.       -- (25)
    , ("M-p n", appendFilePrompt myXPConfig "$HOME/NOTES")
      -- shell prompt.
    , ("M-p s", sshPrompt myXPConfig)                         -- (26)

      -- some searches.
    , ("M-/", submap . mySearchMap $ myPromptSearch)            -- (19,20)
    , ("M-C-/", submap . mySearchMap $ mySelectSearch)          -- (19,20)

    -- some random utilities.
    , ("M-C-c", spawn "dzen-cal")  -- calendar
    , ("<Print>", spawn "scrot")
    , ("C-<Print>", spawn "sleep 0.2; scrot -s")
    ]

newCodeWS :: X ()
newCodeWS = withWindowSet $ \w -> do
  let wss = W.workspaces w
      cws = map W.tag $ filter (\ws -> "code" `isPrefixOf` W.tag ws && isJust (W.stack ws)) wss
      num = head $ [0..] \\ catMaybes (map (readMaybe . drop 4) cws)
      new = "code" ++ show num
  when (not $ new `elem` (map W.tag wss)) $ addWorkspace new
  windows $ W.view new
 where readMaybe s = case reads s of
                       [(r,_)] -> Just r
                       _       -> Nothing

-- Perform a search, using the given method, based on a keypress
mySearchMap method = M.fromList $                               -- (0b)
        [ ((0, xK_g), method google)                            -- (20)
        , ((0, xK_w), method wikipedia)                         --  "
        , ((0, xK_h), method hoogle)                            --  "
        , ((shiftMask, xK_h), method hackage)
        , ((0, xK_s), method scholar)                           --  "
        , ((0, xK_m), method mathworld)                         --  "
        , ((0, xK_p), method maps)                              --  "
        , ((0, xK_d), method dictionary)                        --  "
        , ((0, xK_a), method alpha)                             --  "
        , ((0, xK_l), method lucky)                             --  "
        , ((0, xK_i), method images)
        ]

-- Prompt search: get input from the user via a prompt, then
--   run the search in firefox and automatically switch to the "wb"
--   workspace
myPromptSearch (SearchEngine _ site)
  = inputPrompt myXPConfig "Search" ?+ \s ->                    -- (27)
      (search "firefox" site s >> viewWeb)                      -- (0,20)

-- Select search: do a search based on the X selection
mySelectSearch eng = selectSearch eng >> viewWeb                -- (20)

-- Switch to the "web" workspace
viewWeb = windows (W.view "web")                                -- (0,0a)

-- some nice colors for the prompt windows to match the dzen status bar.
myXPConfig = defaultXPConfig                                    -- (23)
    { fgColor = "#a8a3f7"
    , bgColor = "#3f3c6d"
    }

-- Set up a customized manageHook (rules for handling windows on
--   creation)
myManageHook :: ManageHook                                      -- (0)
myManageHook = composeAll $
                   -- auto-float certain windows
                 [ className =? c --> doCenterFloat | c <- myFloats ] -- (4)
                 ++
                 [ fmap (t `isPrefixOf`) title --> doFloat | t <- myFloatTitles ]
                 ++
                   -- send certain windows to certain workspaces
                 [ className =? "Rhythmbox" --> doF (W.shift "music") -- (0,0a)
                   -- unmanage docks such as gnome-panel and dzen
                 , manageDocks                                     -- (3)
                   -- manage the scratchpad terminal window
                 , namedScratchpadManageHook scratchpads           -- (30)
                 , appName =? "xbuffy-main" --> doFloatAt 0.92 0.66
                 , appName =? "xbuffy-aux"  --> doFloatAt 0.92 0.81
                 ]
    -- windows to auto-float
    where myFloats = [ "Volume"
                     , "XClock"
                     , "Network-admin"
                     , "Xmessage"
                     , "gnome-search-tool"
                     , "Qjackctl.bin"
                     , "Icfp"
                     , "Floating"
                     , "Game"
                     ]
          myFloatTitles = ["Bridge Bid", "Pong", "Floating"]

-- specify a custom layout hook.
myLayoutHook =

    -- automatically avoid overlapping my dzen status bar.
    avoidStrutsOn [U] $                                        -- (3)

    -- make manual gap adjustment possible.
    gaps (zip [U,D,L,R] (repeat 0)) $

    -- start all workspaces in my home directory, with the ability
    -- to switch to a new working dir.                          -- (10,11)
    workspaceDir "~" $

    -- navigate directionally rather than with mod-j/k
    configurableNavigation (navigateColor "#00aa00") $          -- (8)

    -- ability to toggle between fullscreen, reflect x/y, no borders,
    -- and mirrored.
    mkToggle1 NBFULL $                                  -- (14)
    mkToggle1 REFLECTX $                                -- (14,13)
    mkToggle1 REFLECTY $                                -- (14,13)
    mkToggle1 NOBORDERS $                               --  "
    mkToggle1 MIRROR $                                  --  "

    -- borders automatically disappear for fullscreen windows.
    smartBorders $                                              -- (7)

    -- "web" and "irc" start in Full mode and can switch to tiled...
    onWorkspaces ["web","irc"] (Full ||| myTiled) $               -- (10,0)

    -- ...whereas all other workspaces start tall and can switch
    -- to a grid layout with the focused window magnified.
    myTiled |||           -- resizable tall layout
    Mag.magnifier Grid |||                                      -- (15,6)
    TwoPane (3/100) (1/2)

-- use ResizableTall instead of Tall, but still call it "Tall".
myTiled = named "Tall" $ ResizableTall 1 0.03 0.5 []            -- (9,5)