Richard Riley's web site (inprogress)
The XMonad Window Manager
Table of Contents
XMonad
Overview
I have recently switched to using the superb XMonad Window Manager which is a tiling Window Manager written using the functional language Haskell.
XMonad provides the following advantages over metacity (Gnome's default Window Manager)
- Uses much less resources
- programmable using Haskell
- Much easier "keyboard only" navigation (although mouse still recommended for screenshots etc).
- Xinerama multi display integration
Haskell
Haskell is a real challenge for someone more familiar with procedural imperatives language programming, but some good tutorials exist and I can heartily recommend the Real World Haskell tutorial.
Haskell Emacs Integration
A haskell mode exists : editing Haskell with Emacs One thing that niggled me was the poor integration of Haskell help in Emacs which encompassed XMonad and XMonad-Contrib. Thanks to the Hayoo guys for giving me the right URL signature with which I added a bit of eLisp. You can integrate Hayoo with emacs as described here: Integrating Hayoo with Emacs with Browe Apropos Url.
Alternatively the following snippets give you something to start with:
(defun rgr/hayoo()
(interactive)
(let* ((default (region-or-word-at-point))
(term (read-string (format "Hayoo for the following phrase (%s): "
default))))
(let ((term (if (zerop(length term)) default term)))
(browse-url (format "http://holumbus.fh-wedel.de/hayoo/results/hayoo.html?query=%s&start" term)))))
(define-key haskell-mode-map (kbd "<f3>") (lambda()(interactive)(rgr/hayoo)))
My XMonad Configuration
I had used XDM and xsession. I moved back to GDM and Gnome : XMonad and Gnome
Too many things simply didnt work properly without "real" Gnome. I got tired of chasing down what.
Here is my root user's .Xdefaults which make uxvrt have a red tinge when I am in the shell as root:
*background: darkslategrey *font: -adobe-courier-medium-r-normal-*-12-100-*-*-m-*-iso8859-1 *foreground: white urxvt*transparent:true urxvt*font: -adobe-courier-medium-r-normal-*-12-100-*-*-m-*-iso8859-1 urxvt*tintColor:red urxvt*saveLines:12000 urxvt*scrollBar:true urxvt*scrollBar_right:false urxvt*scrollstyle:rxvt
Here is a screenshot
My .xsession file
Note that I dont use this anymore. I now use gnome. See my .gnomerx below
#!/bin/bash # if [ -f $HOME/.bash_env ]; then # source $HOME/.bash_env # fi # source $HOME/bin/xmod # export WINDOW_MANAGER=xmonad # pidof xcompmgr || xcompmgr -c -C -F & # pidof emacs || emacs --daemon & # gnome-session & # exec xmonad
My .gnomerc
if [ -f ~/.bash_env ]; then
. ~/.bash_env
fi
if [ -f ~/.xmodmaprc ]; then
xmodmap ~/.xmodmaprc
fi
My .screenrc
This is nice. Using screen in conjunction with urxvt and xmonad. See the xmonad.hs for how it launches/hides the screen session.
# For a complete list of available commands, see http://bit.ly/jLtj
# Added to by Richard G. Riley <rgr@richardriley.net>
# Message to display in the status line when activity is detected in a
# monitored window.
activity "activity in %n (%t) [%w:%s]~"
# Detach session on hangup instead of terminating screen completely.
autodetach on # default: on
# When a bell character is sent to a background window, screen displays a
# notification in the message line. The notification message can be re-defined
# by this command.
bell_msg "bell in %n (%t) [%w:%s]~"
# This command controls the display of the window captions. Normally a caption
# is only used if more than one window is shown on the display.
caption always "%{= kw}%?%-Lw%?%{+b kw}%n*%t%f %?(%u)%?%{= kw}%?%+Lw%?"
# Select line break behavior for copying.
crlf off # default: off
# Select default utmp logging behavior.
#deflogin off # default: on
# Set default lines of scrollback.
defscrollback 300 # default: 100
# If set to 'on', screen will append to the 'hardcopy.n' files created by the
# command hardcopy; otherwise, these files are overwritten each time.
hardcopy_append off # default: off
# This command configures the use and emulation of the terminal's hardstatus
# line. The type 'lastline' will reserve the last line of the display for the
# hardstatus. Prepending the word 'always' will force screen to use the type
# even if the terminal supports a hardstatus line.
hardstatus alwayslastline "%{+b kr}[ %H ] %{ky} Load: %l %-=%{kb} %c %Y.%m.%d"
msgwait 15
# Set message displayed on pow_detach (when HUP is sent to screen's parent
# process).
pow_detach_msg "BYE"
# Set the default program for new windows.
shell bash
# Default timeout to trigger an inactivity notify.
silencewait 30 # default: 30
# Change text highlighting. See http://bit.ly/11RDGZ
# sorendition gK
# Do NOT display copyright notice on startup.
startup_message off # default: on
# Set $TERM for new windows. I have more luck with 'linux' than Terminal's
# default 'xterm-color' (^H problems). Comment out to use the default.
# term gnome-256color
# term xterm-color
# term rxvt-256color
# term xterm-256color
# term screen-256color
term xterm-256color
# Tweak termcap, terminfo, and termcapinfo entries for best performance.
termcap linux 'AF=\E[3%dm:AB=\E[4%dm'
termcap xterm-color 'AF=\E[3%dm:AB=\E[4%dm'
terminfo linux 'AF=\E[3%p1%dm:AB=\E[4%p1%dm'
terminfo xterm-color 'AF=\E[3%p1%dm:AB=\E[4%p1%dm'
# Allow xterm / Terminal scrollbars to access the scrollback buffer. This
# enables the behavior you'd expect, instead of losing the content that scrolls
# out of the window.
termcapinfo linux ti@:te@
termcapinfo xterm-color ti@:te@
# Use visual bell instead of audio bell.
vbell off # default: ???
# Message to be displayed when the visual bell is triggered.
vbell_msg " *beep* "
# screen -t EMACS 1 edit -nw
# screen -t RSS 2 myrss
# screen -t EXIM$ 8 ssh richardriley.net /home/shamrock/bin/maillog
screen -t BASH 0 bash
.xmodmaprc : keyboard modifying using xmodmap
remove Lock = Caps_Lock add Mod4 = Caps_Lock remove Mod4 = Super_R remove control = Super_R add Mod3 = Super_R
my .Xdefaults
*foreground: white *background: black *cursorColor:green #include "/home/shamrock/.emacs.d/.xEmacs" XTerm*backarrowKey: false XTerm*cursorBlink: true XTerm*metaSendsEscape:true XTerm*eightBitInput: False XTerm*modifier: meta XTerm*termName: xterm-256color XTerm*faceName: Inconsolata XTerm*faceSize: 10 XTerm:*font: "-*-lucida sans typewriter-medium-*-*-*-12-*-*-*-*-*-*-*" Emacs:*font: "-*-lucida sans typewriter-medium-*-*-*-12-*-*-*-*-*-*-*" XTerm*background: #3f3f3f XTerm*foreground: white
My xmonad.hs file
Particularly nice is the use of urxvt for scratchpad and default terminal which in turn connects to a screen session.
{-# LANGUAGE ScopedTypeVariables #-}
-----------------------------------------
-- xmonad.hs
-- Richard G. Riley <rgr@richardriley.net>
-- Thanks to the #xmonad chaps
-- on freednode IRC for help and advice.
-------------------------------------------
import XMonad
import XMonad.Core
import Data.List
import qualified XMonad.StackSet as W
import Control.OldException
import Control.Monad
import DBus
import DBus.Connection
import DBus.Message
import XMonad
import XMonad.Config.Gnome
import XMonad.Hooks.DynamicLog
import XMonad.Actions.GridSelect
import XMonad.Actions.MouseResize
import XMonad.Actions.CycleWS
import XMonad.Actions.CycleWindows (rotFocusedUp, rotFocusedDown)
import XMonad.Actions.RotSlaves
import XMonad.Actions.PerWorkspaceKeys
import qualified XMonad.Actions.Submap as SM
import qualified XMonad.Actions.Search as S
import XMonad.Actions.WindowBringer
import XMonad.Actions.WindowGo
import qualified Data.Map as M
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers
import XMonad.Hooks.SetWMName
import XMonad.Layout.Circle
import XMonad.Layout.DragPane
import XMonad.Layout.IM
import XMonad.Layout.Grid
import XMonad.Layout.NoBorders
import XMonad.Layout.PerWorkspace
import XMonad.Layout.Monitor
import XMonad.Layout.MultiToggle
import XMonad.Layout.MultiToggle.Instances
import XMonad.Layout.Reflect
import XMonad.Layout.SimpleFloat
import XMonad.Layout.WindowArranger
import XMonad.Prompt
import XMonad.Prompt.AppLauncher as AL
import XMonad.Prompt.Shell
import XMonad.Prompt.Ssh
import XMonad.Util.Run
import qualified XMonad.StackSet as Window
import XMonad.Util.EZConfig(additionalKeys)
import XMonad.Util.Scratchpad
import XMonad.Util.NamedScratchpad
import System.Posix.Unistd (getSystemID, nodeName)
import System.Environment (getEnvironment)
import Graphics.X11.Xlib
myWorkSpaces = ["Desktop", "TV" ,"gimp"]
myManageHook = composeAll . concat $
[
[fmap(i `isPrefixOf`) resource --> doIgnore | i <- myIgnores]
,[fmap(f `isPrefixOf`) resource --> doCenterFloat | f <- myFloats]
,[
className =? "Gimp" --> doShift "gimp"
, className =? "MPlayer" --> doShift "TV"
, className =? "MPlayer" --> (ask >>= doF . W.sink)
,isDialog --> doCenterFloat
,isFullscreen --> doFullFloat
]
]
where
myFloats = ["Gnome-system-monitor","Vncviewer", "Steam", "xvidcap", "Xvidcap", "recordMyDesktop","screensaver","gnome-panel","ktorrent","Ddd","GPicker","gpicker", "barrybackup","pinentry-gtk-2","recordMyDesktop"]
myIgnores = ["ddd", "bsh-Interpreter","Do","gnubiff","xsane"]
role = stringProperty "WM_WINDOW_ROLE"
myLayout =
onWorkspace "gimp" (avoidStruts $ mouseResize $ windowArrange $ withIM 0.25 (Role "gimp-toolbox") Full) $
onWorkspace "TV" (smartBorders $ avoidStruts ( Full ||| simpleFloat)) $
onWorkspace "VM" (smartBorders Full) $
avoidStruts $ mouseResize $ windowArrange $ mkToggle (single REFLECTY) $ mkToggle (single REFLECTX) $ mkToggle (single MIRROR) $ mkToggle(NOBORDERS??FULL??SMARTBORDERS??EOT) $ (Tall 1 (3/100) (1/2) ||| dragPane Horizontal 0.1 0.5||| Grid ||| Circle )
myFocusFollowsMouse :: Bool
myFocusFollowsMouse = False
-- myTerminal = "urxvt -name scratchpad -e screen -q -S rgr -d -R"
-- myTerminal = "xterm -e myscreen"
myTerminal = "xterm -name scratchpad -e screen -q -S rgr -d -R"
-- myTerminal = "gnome-terminal"
-- myFadeLogHook :: X ()
-- myFadeLogHook = fadeInactiveLogHook fadeAmount
-- where fadeAmount = 0.5
scratchpads = [
-- run htop in xterm, find it by title, use default floating window placement
NS "iceweasel" "iceweasel -a icepop" (className =? "Iceweasel") nonFloating ,
NS "emacs" "edit" (className =? "Emacs") nonFloating ,
NS "unison" "unison-gtk" (className =? "unison-gtk") nonFloating ,
-- 1/6 of screen width from the left, 1/6 of screen height
-- from the top, 2/3 of screen width by 2/3 of screen height
NS "htop" "xterm -name htop -e htop" (title =? "htop")
(customFloating $ W.RationalRect (1/3) (1/8) (2/3) (1/2)) ,
NS "newsbeuter" "xterm -e myrss" (title =? "myrss")
(customFloating $ W.RationalRect (1/2) (0) (1/2) (1/4))
] where role = stringProperty "WM_WINDOW_ROLE"
isLightHost :: String -> Bool
isLightHost hostname = hostname `elem` ["X30","PUB","Hermes"]
-- This retry is really awkward, but sometimes DBus won't let us get our
-- name unless we retry a couple times.
getWellKnownName :: Connection -> IO ()
getWellKnownName dbus = tryGetName `catchDyn` (\ (DBus.Error _ _) ->
getWellKnownName dbus)
where
tryGetName = do
namereq <- newMethodCall serviceDBus pathDBus interfaceDBus "RequestName"
addArgs namereq [String "org.xmonad.Log", Word32 5]
sendWithReplyAndBlock dbus namereq 0
return ()
main = withConnection Session $ \ dbus -> do
putStrLn "Getting well-known name."
getWellKnownName dbus
putStrLn "Got name, starting XMonad."
host <- fmap nodeName getSystemID
xmonad myConfig
{ logHook = dynamicLogWithPP $ defaultPP {
ppOutput = \ str -> do
let str' = "<span font=\"Terminus 9 Bold\">" ++ str ++
"</span>"
str'' = sanitize str'
msg <- newSignal "/org/xmonad/Log" "org.xmonad.Log"
"Update"
addArgs msg [String str'']
-- If the send fails, ignore it.
send dbus msg 0 `catchDyn`
(\ (DBus.Error _name _msg) ->
return 0)
return ()
, ppTitle = pangoColor "#003366" . shorten 50
, ppCurrent = pangoColor "#006666" . wrap "[" "]"
, ppVisible = pangoColor "#663366" . wrap "(" ")"
, ppHidden = wrap " " " "
, ppUrgent = pangoColor "red"
}
}
myConfig = gnomeConfig {
manageHook = namedScratchpadManageHook scratchpads <+> manageDocks <+> myManageHook
,layoutHook = myLayout
, startupHook = startupHook gnomeConfig >> setWMName "LG3D"
, workspaces= myWorkSpaces
, modMask = mod4Mask
, focusFollowsMouse = False
, terminal = myTerminal
} `additionalKeys` [
-- scrot is a nicely configurable screen shot utility
((0, xK_Print), spawn "scrot -s -d 5 -q50 'shot-%Y%m%d-%H.%M.%S.png' -e 'mv $f ~/tmp/'")
,((modMask myConfig , xK_Print ), spawn "sleep 0.2;scrot -d5 -q50 -s 'shot-%Y%m%d-%H.%M.%S.png' -e 'eog $f'")
,((modMask myConfig, xK_b), bringMenu)
,((modMask myConfig, xK_g), goToSelected defaultGSConfig)
,((modMask myConfig.|. shiftMask, xK_s), SM.submap $ searchEngineMap S.selectSearch)
,((modMask myConfig, xK_s), SM.submap $ searchEngineMap $ S.promptSearch defaultXPConfig)
,((modMask myConfig, xK_p), shellPrompt defaultXPConfig)
, ((modMask myConfig , xK_F1), AL.launchApp defaultXPConfig "gnome-terminal -x info " )
-- ,((modMask myConfig , xK_F1), manPrompt defaultXPConfig)
,((modMask myConfig .|. shiftMask, xK_o), spawn "ooffice -calc")
,((mod3Mask, xK_space), spawn "gnome-do")
,((modMask myConfig .|. shiftMask, xK_g), spawn "gimp")
,((modMask myConfig .|. shiftMask, xK_n), spawn "pcmanfm")
,((modMask myConfig .|. shiftMask, xK_v), bindOn[("TV",spawn "iceweasel -P tv"),("",spawn "iceweasel -a icepop -P default")])
,((modMask myConfig .|. shiftMask, xK_i), namedScratchpadAction scratchpads "iceweasel")
,((modMask myConfig .|. shiftMask, xK_u), namedScratchpadAction scratchpads "unison")
,((modMask myConfig .|. shiftMask, xK_p), namedScratchpadAction scratchpads "htop")
,((modMask myConfig .|. shiftMask, xK_m), spawn "ssh hermes xterm -e htop")
,((modMask myConfig .|. shiftMask, xK_e), namedScratchpadAction scratchpads "emacs")
,((modMask myConfig .|. shiftMask, xK_r), namedScratchpadAction scratchpads "newsbeuter")
,((modMask myConfig .|. shiftMask, xK_s), spawn "su-to-root -X -c /usr/sbin/synaptic")
,((modMask myConfig .|. controlMask, xK_x), spawn "gxmessage -wrap -bg black -fg green `xprop | grep WM_`") -- query X resources
,((modMask myConfig .|. shiftMask, xK_t), scratchpadSpawnActionCustom myTerminal)
-- ,((modMask myConfig .|. shiftMask, xK_t), scratchpadSpawnActionCustom "gnome-terminal --disable-factory --name scratchpad")
,((modMask myConfig .|. shiftMask, xK_h), sshPrompt defaultXPConfig)
-- workspace management
,((modMask myConfig, xK_Down), nextWS)
,((modMask myConfig, xK_j), rotSlavesDown)
,((modMask myConfig, xK_k), rotSlavesUp)
,((modMask myConfig, xK_u), rotFocusedDown)
,((modMask myConfig, xK_i), rotFocusedUp)
,((modMask myConfig, xK_Up), prevWS)
,((modMask myConfig .|. controlMask, xK_Up), shiftToNext)
,((modMask myConfig .|. controlMask, xK_Down), shiftToPrev)
,((modMask myConfig, xK_Right), nextScreen)
,((modMask myConfig, xK_Left), prevScreen)
,((modMask myConfig .|. controlMask, xK_Right), shiftNextScreen)
,((modMask myConfig .|. controlMask, xK_Left), shiftPrevScreen)
,((modMask myConfig .|. controlMask, xK_z), toggleWS)
,((modMask myConfig ,xK_x), sendMessage $ Toggle MIRROR)
,((modMask myConfig ,xK_f), sendMessage $ Toggle FULL)
,((modMask myConfig ,xK_y), sendMessage $ Toggle REFLECTX)
,((modMask myConfig ,xK_s), sendMessage $ Toggle SMARTBORDERS)
,((modMask myConfig ,xK_b), sendMessage $ Toggle NOBORDERS)
-- ,((modMask myConfig, xK_x), sendMessage (Toggle "Circle"))
-- session management
,((modMask myConfig .|. controlMask, xK_f), withFocused float)
,((modMask myConfig .|. controlMask, xK_Delete), spawn "xkill")
,((modMask myConfig .|. shiftMask, xK_Delete), kill)
,((modMask myConfig .|. controlMask, xK_t), spawn "~/bin/myrootterm") -- root terminal
,((modMask myConfig .|. controlMask, xK_s), spawn "gksu poweroff")
,((modMask myConfig .|. controlMask, xK_r), spawn "gksu reboot")
,((modMask myConfig .|. controlMask, xK_l), spawn "gnome-screensaver-command --lock")
,((modMask myConfig .|. controlMask, xK_v), spawn "gnome-volume-control")
,((modMask myConfig .|. controlMask, xK_o), spawn "sleep 0.5; xset dpms force off")
-- , ((modMask myConfig .|. shiftMask, xK_space), layoutScreens 2 (TwoPane 0.5 0.5))
-- , ((modMask myConfig .|. controlMask .|. shiftMask, xK_space), rescreen)
-- multi monitor stuff
,((modMask myConfig .|. controlMask, xK_1), spawn "xrandr -s 0")
,((modMask myConfig .|. controlMask, xK_2), spawn "xrandr -s 1")
,((modMask myConfig .|. controlMask, xK_3), spawn "xrandr -s 2")
]
searchEngineMap method = M.fromList
[((0, xK_g), method S.google)
,((0, xK_H), method S.hoogle)
,((0, xK_w), method S.wikipedia)
,((0, xK_i), method S.imdb)
,((0, xK_a), method S.amazon)
,((0, xK_m), method S.maps)
,((0, xK_y), method S.youtube)
,((0, xK_h), method hayoo)
]
where
hayoo = S.searchEngine "Hayoo" "http://holumbus.fh-wedel.de/hayoo/hayoo.html?query="
pangoColor :: String -> String -> String
pangoColor fg = wrap left right
where
left = "<span foreground=\"" ++ fg ++ "\">"
right = "</span>"
sanitize :: String -> String
sanitize [] = []
sanitize (x:rest) | fromEnum x > 127 = "&#" ++ show (fromEnum x) ++ "; " ++
sanitize rest
| otherwise = x : sanitize rest
My xmobar.conf file
Config {
font = "xft:Times mono-10:size=10:antialias=true"
, bgColor = "#cc812a"
, fgColor = "darkblue"
, position = Static { xpos = 800 , ypos = 977, width = 1280, height = 21 }
, lowerOnStart = False
, commands = [
Run Network "eth0" [] 10
, Run Cpu [] 10
, Run Memory [] 10
, Run Swap [] 10
, Run Date "%a %b %_d %H:%M" "date" 10
, Run StdinReader
, Run CoreTemp [] 40
, Run Com "mailcount" ["richardriley.net"] "mailcount" 600
, Run Mail [("INBOX","/home/shamrock/hermes/Maildir/new"),("INBOX.rgr","/home/shamrock/hermes/Maildir/new")]
]
, sepChar = "%"
, alignSep = "}{"
, template = "<fc=#FFFFFF>%StdinReader%</fc>}{%coretemp%|%cpu%|%memory%|%eth0%|<fc=gold>%date%</fc>|<fc=green>(%mailcount%)</fc>"
}
My mailcount script for xmobar IMAP email count
#!/bin/bash
# script for use with xmobar
# Richard Riley - rileyrgdev AT gmail DOT com
if [ "$1" = "" ]; then
echo "needs a hostname. Exit."
exit
fi
host=$1
newmails=$(ssh $host "ls ~/Maildir/new | wc -l")
if [ "$newmails" -eq "0" ]
then
echo "0"
else
echo "**<fc=white>Email:$newmails</fc>**"
fi
Date: 2009-12-08 17:33:39 CET
HTML generated by org-mode 6.33trans in emacs 23
