Xmonad/Config archive/Remi's xmonad.hs

From HaskellWiki
Jump to navigation Jump to search
import Data.Ratio
import Data.List
import Data.Maybe
import Data.Map (Map)
import qualified Data.Map as Map
import Control.Monad
import Control.Monad.Fix (fix)
import Control.Arrow hiding ((|||))
import System.Exit
import System.IO
import XMonad
import qualified XMonad.StackSet as W
import Data.IORef

----- xmonad-contrib -----
import qualified XMonad.Actions.FlexibleResize as FlexibleResize
import XMonad.Actions.CycleWS

import XMonad.Layout.DragPane (dragPane, DragType(..))
import XMonad.Layout.NoBorders (smartBorders)
import XMonad.Layout.PerWorkspace (onWorkspace, onWorkspaces)
import XMonad.Layout.LayoutHints (layoutHints)

-- xprop -f _NET_WM_STRUT 32c -set _NET_WM_STRUT '0, 0, 16, 0'
--import qualified XMonad.Hooks.ManageDocks as ManageDocks
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageHelpers (doCenterFloat)
import XMonad.Hooks.UrgencyHook

import XMonad.Util.Run

main = do
    xmobar <- spawnPipe "xmobar"
    -- the next N new windows will be floated
    floatNextWindows <- newIORef 0
    xmonad $ withUrgencyHook dzenUrgencyHook $ defaultConfig
        { terminal      = "urxvt"
        , layoutHook    = layoutH
        , manageHook    = manageH floatNextWindows
        , workspaces    = ["music", "chat", "web"] ++ map show [4 .. 9 :: Int]
        , defaultGaps   = [(16,0,0,0)]
        , modMask       = mod4Mask
        , keys          = keyB floatNextWindows
        , mouseBindings = mouseB
        , logHook       = dynamicLogWithPP $ defaultPP
                                {ppCurrent  = xmobarColor "yellow" ""
                                ,ppHidden   = const ""
                                ,ppLayout   = \s -> case fromMaybe s $ stripPrefix "Hinted " s of
                                               "Mirror Tall"    -> "Wide"
                                               s                -> s
                                ,ppSep      = " | "
                                ,ppTitle    = xmobarColor "#aaaabb" "" . shorten 40
                                ,ppOutput   = hPutStrLn xmobar
                                ,ppExtras   = [do
                                                    i <- io $ readIORef floatNextWindows
                                                    return $ Just $ if i == 0
                                                                        then "-"
                                                                        else show i
                                              ]
                                }
        }

layoutH = layoutHints . smartBorders
        $ onWorkspace "music"   (tiled
                                ||| Mirror tiled
                                ||| Full
                                )
        $ onWorkspace "chat"    (tiled
                                ||| Mirror tiled
                                ||| Full
                                )
        $ onWorkspace "web"     (Mirror tiled2
                                ||| tiled2
                                ||| Full
                                )
        $ Mirror tiled
            ||| tiled
            ||| Full
            ||| dragPane Horizontal 0.1 0.5
  where
     tiled  = Tall 1 (3 % 100) (3 % 5)
     tiled2 = Tall 1 (3 % 100) (4 % 5)

manageH :: IORef Integer -> ManageHook
manageH floatNextWindows = composeAll $ concat
                [[ className =? name        --> doFloat                 | name <- floats ]
                ,[ className =? name        --> doF (W.shift workspace) | (name, workspace) <- shifts ]
                ,[ resource  =? res         --> doIgnore                | res <- ignores ]
                ,[ (> 0) `liftM` io (readIORef floatNextWindows)
                                            --> do io (modifyIORef floatNextWindows pred) >> doCenterFloat ]
                ]
    where
        floats  = ["MPlayer", "Gimp", "Blender", "Xmessage", "Cinelerra", "foobillard", "xaos", "Ddd", "xine"]
        shifts  = ("Firefox-bin",   "web")
                : ("Pidgin",        "chat")
                : zip ["Qmpdclient", "Gmpc", "Sonata"] (repeat "music")
        ignores = ["desktop_window", "kdesktop"]

keyB :: IORef Integer -> XConfig Layout -> Map (KeyMask, KeySym) (X ())
keyB floatNextWindows conf@(XConfig {modMask = modMask}) = Map.fromList $
    -- launching and killing programs
    [ ((modMask,               xK_z     ), spawn $ XMonad.terminal conf) -- %! Launch terminal
    , ((modMask .|. shiftMask, xK_z     ), runInTerm "" "zsh -l") -- %! Launch terminal
    , ((modMask,               xK_a     ), spawn "firefox") -- %! Launch a firefox
    , ((modMask,               xK_p     ), spawn "exe=`dmenu_path | dmenu` && eval \"exec $exe\"") -- %! Launch dmenu
    , ((modMask .|. shiftMask, xK_p     ), spawn "exe=`dmenu_path | dmenu` && eval \"exec urxvt -e $exe\"") -- %! Launch dmenu
    , ((modMask,               xK_x     ), kill) -- %! Close the focused window
    , ((modMask .|. shiftMask, xK_x     ), withDisplay $ \d ->
                                            withFocused $ \w -> io $ do
                                                killClient d w
                                                return ()
                                            ) -- %! Kill the focused window
    , ((modMask,            xK_KP_Right ), spawn "mpc next")
    , ((modMask,            xK_KP_Left  ), spawn "mpc prev")
    , ((modMask,            xK_KP_Up    ), spawn "mpc toggle")
    , ((modMask,            xK_KP_Down  ), spawn "mpc play")
    , ((modMask,            xK_Pause    ), spawn "xscreensaver-command -lock")
    , ((modMask,            xK_Print    ), spawn "scrot -q10 'shot-%Y%m%d-%H.%M.%S.png'")
    , ((modMask .|. shiftMask, xK_Print ), spawn "sleep 0.2; scrot -q10 -s 'shot-%Y%m%d-%H.%M.%S.png'")
    , ((modMask,            xK_u        ), runInTerm "" "mutt")

    , ((modMask,               xK_space ), sendMessage NextLayout) -- %! Rotate through the available layout algorithms
    , ((modMask .|. shiftMask, xK_space ), setLayout $ XMonad.layoutHook conf) -- %!  Reset the layouts on the current workspace to default

    , ((modMask,               xK_n     ), refresh) -- %! Resize viewed windows to the correct size
    , ((modMask,               xK_f     ), io (modifyIORef floatNextWindows succ) >> logHook conf)
    , ((modMask .|. shiftMask, xK_f     ), io (modifyIORef floatNextWindows (const 0)) >> logHook conf)

    -- move focus up or down the window stack
    , ((modMask,               xK_Tab   ), windows W.focusDown) -- %! Move focus to the next window
    , ((modMask,               xK_j     ), windows W.focusDown) -- %! Move focus to the next window
    , ((modMask,               xK_k     ), windows W.focusUp  ) -- %! Move focus to the previous window
    , ((modMask,               xK_m     ), windows W.focusMaster  ) -- %! Move focus to the master window

    -- modifying the window order
    , ((modMask,               xK_Return), windows W.swapMaster) -- %! Swap the focused window and the master window
    , ((modMask .|. shiftMask, xK_j     ), windows W.swapDown  ) -- %! Swap the focused window with the next window
    , ((modMask .|. shiftMask, xK_k     ), windows W.swapUp    ) -- %! Swap the focused window with the previous window

    -- resizing the master/slave ratio
    , ((modMask,               xK_h     ), sendMessage Shrink) -- %! Shrink the master area
    , ((modMask,               xK_l     ), sendMessage Expand) -- %! Expand the master area

    -- floating layer support
    , ((modMask,               xK_t     ), withFocused $ windows . W.sink) -- %! Push window back into tiling

    -- increase or decrease number of windows in the master area
    , ((modMask              , xK_comma ), sendMessage (IncMasterN 1)) -- %! Increment the number of windows in the master area
    , ((modMask              , xK_period), sendMessage (IncMasterN (-1))) -- %! Deincrement the number of windows in the master area

    -- toggle the status bar gap
    , ((modMask              , xK_b     ), modifyGap (\i n -> let x = (XMonad.defaultGaps conf ++ repeat (0,0,0,0)) !! i in if n == x then (0,0,0,0) else x)) -- %! Toggle the status bar gap

    -- quit, or restart
    , ((modMask .|. shiftMask, xK_q     ), io (exitWith ExitSuccess)) -- %! Quit xmonad
    , ((modMask              , xK_q     ), broadcastMessage ReleaseResources >> restart "xmonad" True) -- %! Restart xmonad

    -- edit xmonad.hs
    , ((modMask              , xK_e     ), spawn "gvim $HOME/.xmonad/xmonad.hs") -- %! edit xmonad.hs

    ]
    -- goto and/or shift to the next/prev workspace
    ++ prevNextWorkspaceBindings modMask xK_Left xK_Right
    ++
    -- mod-[1..9] %! Switch to workspace N
    -- mod-shift-[1..9] %! Move client to workspace N
    -- mod-shift-control-[1..9] %! Move client and switch to workspace N
    [((m .|. modMask, k), windows $ f i)
        | (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9]
        , (f, m) <- [(W.greedyView, 0)
                    ,(W.shift, shiftMask)
                    ,(\i -> W.greedyView i . W.shift i, shiftMask .|. controlMask)
                    ]]

-- Not needing a mouse doesn't mean not using it
button6     =  6 :: Button
button7     =  7 :: Button
button8     =  8 :: Button
button9     =  9 :: Button
button10    = 10 :: Button
button11    = 11 :: Button
button12    = 12 :: Button
button13    = 13 :: Button
button14    = 14 :: Button
button15    = 15 :: Button

mouseB :: XConfig Layout -> Map (KeyMask, Button) (Window -> X ())
mouseB (XConfig {XMonad.modMask = modMask}) = Map.fromList $
    -- mod-button1 %! Set the window to floating mode and move by dragging
    [ ((modMask                 , button1), (\w -> focus w >> mouseMoveWindow w))
    -- mod-button2 %! Raise the window to the top of the stack
    , ((modMask                 , button2), (\w -> focus w >> windows W.swapMaster))
    -- mod-button3 %! Set the window to floating mode and resize by dragging
    , ((modMask                 , button3), \w -> focus w >> FlexibleResize.mouseResizeWindow w)

    -- Mouse scroll wheel to raise/lower windows
    , ((modMask                 , button5), \w -> windows W.swapDown)
    , ((modMask                 , button4), \w -> windows W.swapUp  )

    , ((0                       , button9), \w -> spawn "mpc next")
    , ((0                       , button8), \w -> spawn "mpc prev")
    , ((0                       , button10),\w -> spawn "mpc toggle")
    , ((modMask                 , button10),\w -> spawn "mpc random")
    ]
    -- Horizontal scroll wheel for next/prev workspace
    ++ map (second const) (prevNextWorkspaceBindings modMask button13 button14)

prevNextWorkspaceBindings :: KeyMask -> a -> a -> [((KeyMask, a), X ())]
prevNextWorkspaceBindings modMask prev next =
    [ ((modMask,               next),   nextWS)
    , ((modMask,               prev),   prevWS)
    , ((modMask .|. shiftMask, next),   shiftToNext)
    , ((modMask .|. shiftMask, prev),   shiftToPrev)
    , ((modMask .|. shiftMask .|. controlMask
                             , next),   shiftToNext >> nextWS)
    , ((modMask .|. shiftMask .|. controlMask
                             , prev),   shiftToPrev >> prevWS)
    ]