-- -*- haskell -*-
import Monad (liftM)
import XMonad hiding ( (|||) )
import XMonad.Core
import System.Exit
import qualified XMonad.StackSet as W
import qualified Data.Map as M
import XMonad.Hooks.DynamicLog hiding (shorten)
{-import XMonad.Hooks.ManageHelpers-}
import XMonad.Actions.CycleWS
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.EwmhDesktops
import XMonad.Actions.DwmPromote
import XMonad.Actions.UpdatePointer
import XMonad.Actions.WindowGo
{-import XMonad.Actions.WindowNavigation-}
import XMonad.Hooks.UrgencyHook
import XMonad.Util.Run (safeSpawn, unsafeSpawn, runInTerm, spawnPipe)
import System.IO
import XMonad.Prompt
import XMonad.Prompt.Shell
import XMonad.Prompt.RunOrRaise
import XMonad.Util.WorkspaceCompare
import XMonad.Util.EZConfig
import XMonad.Actions.Warp
{-import Data.Ratio-}
import Graphics.X11.Xlib.Extras
import Foreign.C.Types (CLong)
import XMonad.Actions.TagWindows
import XMonad.Layout.IM
import Data.Ratio ((%))
import XMonad.Layout.PerWorkspace
{-import XMonad.Layout.LayoutHints (layoutHints)-}
import XMonad.Layout.NoBorders
import XMonad.Layout.DragPane (dragPane, DragType(..))
import XMonad.Layout.Gaps
{-import XMonad.Layout.ToggleLayouts-}
import XMonad.Layout.Tabbed
import XMonad.Layout.ResizableTile
import XMonad.Layout.Grid
import XMonad.Layout.Magnifier
import XMonad.Layout.WindowNavigation
import XMonad.Layout.Named
import XMonad.Layout.LayoutCombinators
{-import XMonad.Layout.TabBarDecoration-}
import XMonad.Util.NamedScratchpad
import XMonad.Util.NamedWindows (getName)
import Data.List
import Data.Char
import XMonad.Hooks.ManageHelpers
role :: Query String
role = stringProperty "WM_WINDOW_ROLE"
notFloating :: Query Bool
notFloating = ask >>= \w -> liftX $ withWindowSet $ return . not . M.member w . W.floating
myTerminal = "urxvt"
myBorderWidth = 1
myModMask = mod4Mask
myNumlockMask = mod2Mask
myWorkspaces = ["web", "work" ,"chat", "mics"]
myNormalBorderColor = "#555555"
myFocusedBorderColor = "black"
----------Key bindings
myKeys = \conf -> mkKeymap conf $
[ ("M-S-<Return>", spawn $ XMonad.terminal conf)
, ("M-<F1>", runOrRaisePrompt defaultXPConfig)
, ("M-C-<Esc>", spawn $ "xkill")
, ("M-<Space>", sendMessage NextLayout)
, ("M-S-<Space>", setLayout $ XMonad.layoutHook conf)
, ("M-<Tab>", windows W.focusDown)
, ("M-j", windows W.focusDown)
, ("M-S-<Tab>", windows W.focusUp)
, ("M-k", windows W.focusUp)
, ("M-m", windows W.focusMaster)
, ("M-S-k", windows W.swapDown)
, ("M-S-j", windows W.swapUp)
, ("M-b", sendMessage $ ToggleGaps)
, ("M-h", sendMessage Shrink)
, ("M-l", sendMessage Expand)
, ("M-x t", withFocused $ windows . W.sink)
, ("M-,", sendMessage (IncMasterN 1))
, ("M-.", sendMessage (IncMasterN (-1)))
, ("M-S-q", io (exitWith ExitSuccess))
, ("M-q", restart "xmonad" True)
, ("M-p", shellPrompt defaultXPConfig)
, ("M-C-<Left>", prevNonEmptyWS )
, ("M-C-k", prevNonEmptyWS )
, ("M-C-<Right>", nextNonEmptyWS )
, ("M-C-j", nextNonEmptyWS )
, ("M-a", sendMessage MirrorShrink)
, ("M-y", sendMessage MirrorExpand)
, ("M-<Return>", dwmpromote)
, ("M-x M-c", kill)
, ("M-x c", kill)
, ("M-x e", spawn "emacsclient -c -s emacs")
, ("<XF86HomePage>", ror "firefox-beta" (className =? "Firefox"))
, ("<XF86Mail>", ror "krusader" (className =? "Krusader"))
, ("M-w", sendMessage MagnifyMore)
, ("M-e", sendMessage MagnifyLess)
, ("M-<", warpToWindow (1%10) (1%10)) -- Move pointer to currently focused window
, ("M-<XF86Calculator>", namedScratchpadAction scratchpads "ncmpcpp")
, ("M-<XF86Forward>", namedScratchpadAction scratchpads "rtorrent")
, ("M-<XF86Back>", namedScratchpadAction scratchpads "htop")
, ("M-<XF86Explorer>", namedScratchpadAction scratchpads "notes")
, ("<XF86Calculator>", windows (W.view "web"))
, ("<XF86Forward>", windows (W.view "work"))
, ("<XF86Back>", windows (W.view "chat"))
, ("<XF86Explorer>", windows (W.view "mics"))
, ("<XF86AudioRaiseVolume>", spawn "amixer sset \"PCM\" 5+")
, ("<XF86AudioLowerVolume>", spawn "amixer sset \"PCM\" 5-")
, ("M-<XF86AudioRaiseVolume>", spawn "amixer sset \"PCM Headphone\" 5+")
, ("M-<XF86AudioLowerVolume>", spawn "amixer sset \"PCM Headphone\" 5-")
, ("<Scroll_lock>", spawn "xset led 3")
, ("C-<Scroll_lock>", spawn "xset -led 3")
, ("<XF86AudioPlay>", spawn "ncmpcpp play")
, ("<XF86AudioStop>", spawn "ncmpcpp pause")
, ("M-<Left>", sendMessage $ Go L)
, ("M-<Right>", sendMessage $ Go R)
, ("M-<Up>", sendMessage $ Go U)
, ("M-<Down>", sendMessage $ Go D)
, ("M-S-<R>", sendMessage $ Swap R)
, ("M-S-<L>", sendMessage $ Swap L)
, ("M-S-<U>", sendMessage $ Swap U)
, ("M-S-<D>", sendMessage $ Swap D)
, ("<Pause>", unsafeSpawn "import -w root png:$HOME/screenshot--`date +%F--%T`.png")
, ("M-f", sendMessage $ JumpToLayout "full")
, ("M-t", sendMessage $ JumpToLayout "tabs")
, ("<XF86Sleep>", spawn "sudo /sbin/halt")
, ("<XF86Favorites>", spawn "emacsclient -c")
]
++
[ (m ++ i, windows $ f j)
| (i, j) <- zip (map show [1..9]) (XMonad.workspaces conf)
, (m, f) <- [("M-", W.view), ("M-S-", W.shift)]
]
where
nextNonEmptyWS = moveTo Next (WSIs (liftM (not .) isVisible))
prevNonEmptyWS = moveTo Prev (WSIs (liftM (not .) isVisible))
ror x p = runOrRaise x (p <&&> notFloating)
isVisible :: X (WindowSpace -> Bool)
isVisible = do
vs <- gets (map (W.tag . W.workspace) . W.visible . windowset)
return (\w -> (W.tag w) `elem` vs)
myMouseBindings (XConfig {XMonad.modMask = modMask}) = M.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 >> mouseResizeWindow w))
-- you may also bind events to the mouse scroll wheel (button4 and button5)
-- cycle focus
, ((modMask, button4), (\_ -> windows W.focusUp))
, ((modMask, button5), (\_ -> windows W.focusDown))
-- cycle through workspaces
, ((controlMask .|. modMask, button5), nextNonEmptyWS)
, ((controlMask .|. modMask, button4), prevNonEmptyWS)
]
where
nextNonEmptyWS = \_ -> moveTo Next (WSIs (liftM (not .) isVisible))
prevNonEmptyWS = \_ -> moveTo Prev (WSIs (liftM (not .) isVisible))
myLayout = windowNavigation
$ onWorkspace "web" (tabsL
||| fullL
)
$ onWorkspace "mics" (tabsL
||| magL
||| tallL
)
$ onWorkspace "chat" (imL)
$ onWorkspace "work" (tabsL
||| tallL
||| fullL
)
$ onWorkspace "full" fullL
$ tallL
where
bscL = ResizableTall 1 (3 % 1000) (8 % 13) []
tallL= gaps [(U,18), (D,20)] $ bscL
fullL = named "full" $ noBorders Full
imL = named "im" $ gaps [(U,18), (D,20)] $ withIM (1%7) (Role "roster") Grid
tabsL =named "tabs" $ gaps [(U,18), (D,20)] $ tabbed shrinkText oxyTheme
magL = gaps [(U,18), (D,20)] $ magnifiercz (10%15) Grid
-- Configuration for Tabbed
oxyTheme :: Theme
oxyTheme = defaultTheme { inactiveBorderColor = "#696969"
, activeBorderColor = "white"
, activeColor = "#111111"
, inactiveColor = "#212121"
, inactiveTextColor = "#696969"
, activeTextColor = "white"
, fontName = "xft:Terminus-10"
, decoHeight = 18
, urgentColor = "white"
, urgentTextColor = "#77e000"
}
--SendMessage on app up
fromWindowOp :: (Window -> X()) -> ManageHook
fromWindowOp fn = ask >>= \w -> liftX (fn w) >> doF id
fromX :: X () -> ManageHook
fromX op = fromWindowOp $ const op
myManageHook = composeAll
[className =? "Firefox" --> doF (W.shift "web")
, className =? "Gajim.py" --> doF (W.shift "chat")
, className =? "MPlayer" --> doFullFloat
, className =? "Gwenview" --> doFullFloat
, className =? "Okular" --> doFullFloat
{-, className =? "Qutim" [>> doF (W.shift "chat")-}
, className =? "Krusader" --> doF (W.shift "work")
, resource =? "stalonetray" --> doIgnore
, className =? "Dialog" --> doFloat
, title =? "Add-ons" --> doFloat
, title =? "Copying" --> doFloat
, title =? "Downloads" --> doFloat
, title =? "Moving" --> doFloat]
<+> manageDocks
-- Statusbar with workspaces, layout and title
myStatusBar = "dzen2 -x 0 -y 0 -h 18 -ta l -fg '" ++ myDzenFGColor ++
"' -bg '" ++ myDzenBGColor ++ "' -fn '" ++ myFont ++ "' -w 720"
-- Colors, font and iconpath definitions:
myFont = "-*-terminus-*-*-*-*-12-*-*-*-*-*-*-*%"
myIconDir = "/home/kain/.dzen"
myDzenFGColor = "#555555"
myDzenBGColor = "#212121"
myNormalFGColor = "#77e000"
myNormalBGColor = "#000000"
myFocusedFGColor = "#f0f0f0"
myFocusedBGColor = "#333333"
myUrgentFGColor = "#0099ff"
myUrgentBGColor = "#991133"
mySeperatorColor = "#555555"
-- Status bars and logging
myLogHook h = defaultPP
{ ppCurrent = dzenColor myNormalFGColor myDzenBGColor . pad . ("^i(.dzen/corner.xbm)" ++) -- current workspace
, ppVisible = dzenColor "lightgreen" "" . pad -- visible workspaces on other screens
, ppHidden = dzenColor "white" "" . pad . ("^i(.dzen/corner.xbm)" ++) -- hidden workspaces with apps
, ppHiddenNoWindows = dzenColor "#444444" "" . pad -- empty workspaces
, ppUrgent = dzenColor "" myUrgentBGColor -- urgent workspaces
, ppTitle = dzenColor myNormalFGColor "" . pad . dzenEscape -- title of selected window
, ppWsSep = "" -- workspace seperator
, ppSep = dzenEscape "|" -- workspace/layout/title seperator
-- Layout icons
, ppLayout = dzenColor myNormalFGColor "" .
(\ x -> case x of
"tallL" -> pad "^i(/home/kain/.dzen/layout-tall-right.xbm)"
"Mirror Tall" -> pad "^i(/home/kain/.dzen/layout-mirror-bottom.xbm)"
"full" -> pad "^i(/home/kain/.dzen/layout-full.xbm)"
"im" -> pad "^i(/home/kain/.dzen/layout-withim-left1.xbm)"
"IM Hinted ResizableTall" -> pad "^i(/home/kain/.dzen/layout-withim-left2.xbm)"
"IM Mirror Hinted ResizableTall" -> pad "^i(/home/kain/.dzen/layout-withim-left3.xbm)"
"IM Full" -> pad "^i(/home/kain/.dzen/layout-withim-left4.xbm)"
"tabs" -> pad "^i(/home/kain/.dzen/tabs.xbm)"
_ -> pad x
)
, ppOutput = hPutStrLn h
}
myFocusFollowsMouse :: Bool
myFocusFollowsMouse = True
-- Startup hook
--
-- -- Perform an arbitrary action each time xmonad starts or is restarted
-- -- with mod-q. Used by, e.g., XMonad.Layout.PerWorkspace to initialize
-- -- per-workspace layout choices.
-- --
-- -- By default, do nothing.
myStartupHook = do
spawn "/home/kain/.bin/autostart.sh"
--------------- Scratchpads
scratchpads = [ NS "notes" "urxvtc -name terminal" (resource =? "terminal") defaultRect
, NS "htop" "urxvt -name htop -e htop" (title =? "htop") defaultRect
, NS "ncmpcpp" "urxvt -name ncmpcpp -e ncmpcpp" (resource =? "ncmpcpp") smallerRect
, NS "rtorrent" "urxvt -name rtorrent -e dtach -A /tmp/rtorrent.dtach -z rtorrent" (resource =? "rtorrent") smallerRect
] where
defaultRect = Just $ W.RationalRect (1/6) (1/6) (2/3) (2/3)
smallerRect = Just $ W.RationalRect (1/4) (1/6) (1/2) (2/3)
calcRect = Just $ W.RationalRect (3/8) (1/3) (1/4) (1/3)
------------------------------------------------------------------------
{-$ withWindowNavigationKeys [((modMask, xK_Up) WnGo U),((modMask, xk_Down) WnGo D)]-}
--Main
main = do
dzen <- spawnPipe myStatusBar
xmonad $ withUrgencyHook NoUrgencyHook $ defaultConfig {
-- simple stuff
terminal = myTerminal,
focusFollowsMouse = myFocusFollowsMouse,
borderWidth = myBorderWidth,
modMask = myModMask,
numlockMask = myNumlockMask,
workspaces = myWorkspaces,
normalBorderColor = myNormalBorderColor,
focusedBorderColor = myFocusedBorderColor,
-- key bindings
keys = myKeys,
mouseBindings = myMouseBindings,
-- hooks, layouts
layoutHook = myLayout,
manageHook = myManageHook <+> (namedScratchpadManageHook scratchpads),
logHook = dynamicLogWithPP (myLogHook dzen)
,startupHook = myStartupHook
}