Tuesday, April 27, 2010

Xmonad Session

xmonad is a tiling window manager. Tiling managers are good because usually you can see windows in different layouts, switch them dynamically or configure your virtual desktops for particular usage with appropriate layout. Before I was experimenting with awesome but xmonad is the first tiling manager I'm using seriously in each day work. It has a lot of documentation that at first seems overwhelming.

You should be fine to get running by adapting some example configurations. However as I'm irriatted when I should copy-paste something I don't understand I've started to learn haskell (great language). You can find a lot of sources for studying. After understanding the basics I was able to browse xmonad & xmonad-contrib documentation and tweak my own configuration, structure config file as I liked and so on.

As a status bar I use xmobar. I had a problems with XFT support for tabbed layout (xmonad-contrib) which was the problem of compilation, recompiling with correct flags helped. In meantime I've upgraded to *-darcs versions (xmobar in arch repos has a problem with UTF-8). After some initial using I was annoyed with tearing the screen when switching the windows. I've found out it is caused by 'NoBorders' layout modifier, thicker you have borders tearing will be more visible, for now I've stick with 1px borders turned on everywhere.

~/.xmonad/xmonad.hs
import XMonad hiding ( (|||) )
import qualified XMonad.StackSet as W

import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageHelpers
import XMonad.Hooks.SetWMName

-- import XMonad.Layout.BorderResize
import XMonad.Layout.BoringWindows
-- import XMonad.Layout.DragPane
import XMonad.Layout.DwmStyle
import XMonad.Layout.Grid
import XMonad.Layout.LayoutCombinators
-- import XMonad.Layout.Magnifier
-- import XMonad.Layout.Master
-- import XMonad.Layout.Maximize
-- import XMonad.Layout.Minimize
-- import XMonad.Layout.MouseResizableTile
import XMonad.Layout.NoBorders
-- import XMonad.Layout.SimpleFloat
-- import XMonad.Layout.Spacing
import XMonad.Layout.Tabbed
-- import XMonad.Layout.WindowArranger

import XMonad.Prompt
import XMonad.Prompt.AppLauncher
import XMonad.Prompt.AppendFile
-- import XMonad.Prompt.Shell
-- import XMonad.Prompt.Ssh

import XMonad.Util.EZConfig (additionalKeys)
import XMonad.Util.Themes
import XMonad.Util.NamedScratchpad

import System.IO

-- status bar
myStatusBar conf = statusBar "xmobar" myXmobarPP myToggleStrutsKey conf
    where
        myToggleStrutsKey XConfig{modMask = modm} = (modm, xK_b)
        myXmobarPP = defaultPP
            {
                ppCurrent = xmobarColor "green" "" . wrap "[" "]",
                ppVisible = xmobarColor "yellow" "" . wrap "(" ")",
                ppUrgent = xmobarColor "red" "yellow",
                ppTitle = xmobarColor "gray" "" . shorten 60,
                ppLayout = \x -> ""
            }

-- config
myConfig = defaultConfig
        {
            terminal = myTerminal,
            workspaces = myWorkspaces,
            focusFollowsMouse = True,
            borderWidth = 1,
            normalBorderColor = "#000000",
            focusedBorderColor = "#FF0000",
            modMask = myModMask,
            startupHook = setWMName "LG3D",
            manageHook = manageHook defaultConfig <+> namedScratchpadManageHook myScratchpads <+> myManageHook,
            layoutHook = myLayoutHook
        }
        `additionalKeys`
        [
            -- xterm
            ((myModMask, xK_x), spawn "xterm"),
            -- dmenu
            ((myModMask, xK_p), spawn "dmenu_run"),
            -- lock
            ((myModMask .|. shiftMask, xK_l), spawn "sleep 0.5 && lock"),
            -- scrot
            ((controlMask, xK_Print), spawn "sleep 0.2 && scrot -s -d 2 -e 'feh $f'"),
            ((0, xK_Print), spawn "scrot -d 2 -e 'feh $f'"),
            -- prompts
            ((myModMask, xK_g), launchApp defaultXPConfig "gimp"),
            -- ((myModMask .|. shiftMask, xK_n), appendFilePrompt defaultXPConfig "/home/miro/notes"),
            -- scratchpads
            ((myModMask .|. shiftMask, xK_t), namedScratchpadAction myScratchpads "term"),
            ((myModMask .|. shiftMask, xK_h), namedScratchpadAction myScratchpads "htop"),
            -- sound
            ((myModMask, xK_Down), spawn "amixer set PCM 1-"),
            ((myModMask, xK_Up), spawn "amixer set PCM 1+"),
            ((myModMask .|. shiftMask, xK_Down), spawn "amixer set Master 1-"),
            ((myModMask .|. shiftMask, xK_Up), spawn "amixer set Master 1+"),
            ((myModMask .|. shiftMask, xK_m), spawn "amixer set Master toggle"),
            -- vim cheat sheet
            ((myModMask, xK_v), spawn "feh -F /home/miro/archive/incoming/vim/vi-vim-cheat-sheet.gif"),
            -- xrandr
            ((myModMask, xK_F10), spawn "xrandr-bigdesktop-LVDS_DVI && xmonad-session-repair"),
            ((myModMask, xK_F11), spawn "xrandr-bigdesktop-LVDS_VGA && xmonad-session-repair"),
            ((myModMask, xK_F12), spawn "xrandr-bigdesktop-VGA_DVI && xmonad-session-repair")
        ]
    where
        myTerminal = "urxvt"
        myModMask = mod4Mask
        -- workspaces
        myWorkspaces = workspaces defaultConfig
        -- scratchpads
        myScratchpads = [
                NS "term" (myTerminal ++ " -name sp_term") (resource =? "sp_term") (customFloating $ W.RationalRect 0.1 0.1 0.8 0.8),
                NS "htop" (myTerminal ++ " -name sp_htop -e htop") (resource =? "sp_htop") (customFloating $ W.RationalRect 0.05 0.05 0.9 0.9)
            ]
        -- manage hook
        myManageHook = composeOne
            [
                isDialog -?> doFloat,
                className =? "Gimp" -?> doFloat,
                className =? "Skype" -?> doFloat,
                className =? "Pidgin" -?> doFloat
            ]
        -- layout hook
        myLayoutHook = myTabbed       |||
                       Full           |||
                       myTiled        |||
                       Mirror myTiled |||
                       myGrid
            where
                aTheme = (theme deiflTheme)
                myTheme = aTheme
                    {
                        activeBorderColor = activeColor aTheme,
                        inactiveBorderColor = inactiveColor aTheme,
                        urgentBorderColor = urgentColor aTheme,
                        fontName = "xft:Monospace:bold:size=9",
                        decoWidth = 500,
                        decoHeight = 18
                    }
                myTabbed = tabbedBottom shrinkText myTheme
                myTiled = Tall 1 (3/100) (1/2)
                myGrid = dwmStyle shrinkText myTheme Grid

-- main
main = xmonad =<< myStatusBar myConfig
~/.xmobarrc
Config { font = "xft:Monospace:bold:size=9"
       , bgColor = "black"
       , fgColor = "gray"
       , position = TopW L 85
       , lowerOnStart = True
       , commands = [ Run StdinReader
                    , Run Cpu ["-t","","-L","3","-H","50","-n","green","-h","red"] 50
                    , Run CpuFreq ["-t","|","-L","0","-H","2","-n","gray","-h","red"] 50
                    , Run CoreTemp ["-t","|","-L","40","-H","60","-l","lightblue","-n","gray","-h","red"] 50
                    , Run Memory ["-t",""] 50
                    , Run Swap ["-t",""] 50
                    , Run Date "%d.%m|%k:%M" "date" 50
                    ]
       , sepChar = "%"
       , alignSep = "}{"
           , template = "%StdinReader% }{ %cpu%  %cpufreq%  %coretemp%C  %memory%/%swap%  %date%"
       }
~/bin/dmenu_run
#!/bin/sh

/usr/bin/dmenu_run -i -fa "Monospace:bold:size=9" -nb "#333333" -nf "#FFFFFF" -sb "#000000" -sf "#87cefa" -p ">"
~/bin/lock
#!/bin/sh

#xset dpms force off && xscreensaver-command -lock
xset dpms force off && i3lock
#slock
~/bin/pm-suspend
#!/bin/sh

lock &
/usr/sbin/pm-suspend

I start a session by GDM. So I created file /usr/share/xsessions/xmonad.desktop (on archlinux the xmonad package installed the similar file to /etc/X11/sessions/xmonad.desktop which was taking precedence so I've renamed it).

Update: I've switched to using CDM.

/usr/share/xsessions/xmonad.desktop
[Desktop Entry]
Name=XMonad
Comment=This starts XMonad session
Exec=xmonad-session
Icon=
Type=Application

At last my startup script.

~/bin/xmonad-session
#!/bin/sh

xrandr-bigdesktop

gnome-keyring-daemon --start --components=pkcs11
gnome-keyring-daemon --start --components=secrets
gnome-keyring-daemon --start --components=ssh

xset dpms 180 240 300
xsetroot -solid black
xsetroot -cursor_name left_ptr

#nitrogen --restore
#xcompmgr -S &
#xscreensaver -no-splash &

trayer --edge top --align right \
       --width 10 --widthtype request --height 19 --heighttype pixel \
       --SetDockType true --SetPartialStrut true \
       --transparent true --alpha 0 --tint 0x000000 \
       --expand true &

gnome-power-manager &
nm-applet --sm-disable &
parcellite &
#unclutter -idle 2 -root -grab &
#unclutter -idle 2 -root &

xmonad

I'm still learning how to organize xmonad session better, so my configuration is work in progress.

Update: I've quit from using 'unclutter' utility because I had problems to get it working with some other software eager of grabbing mouse. Anyway 'urxvt' has uncluttering feature built in so it's not bugging me a lot.