xmonad.hs

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances, FlexibleContexts, NoMonomorphismRestriction #-}
import XMonad hiding ( (|||) )
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers
import XMonad.Hooks.XPropManage
-- for JAVA:
import XMonad.Hooks.SetWMName
import XMonad.Layout.Combo
import XMonad.Layout.IM
import XMonad.Layout.Grid
import XMonad.Layout.LayoutModifier
import XMonad.Layout.LayoutCombinators
import XMonad.Layout.NoBorders
import XMonad.Layout.PerWorkspace
import XMonad.Layout.ResizableTile
import XMonad.Layout.Tabbed
import XMonad.Layout.ToggleLayouts
import XMonad.Layout.WindowNavigation
import XMonad.Util.Run(spawnPipe)
import XMonad.Util.EZConfig(additionalKeys)
import XMonad.Util.Dmenu
import XMonad.Util.WindowProperties
import System.IO
import XMonad.Actions.CopyWindow
import XMonad.Actions.TagWindows
import XMonad.Prompt
import XMonad.Prompt.Window
import qualified XMonad.StackSet as W
import qualified Data.Map as M
import Data.Ratio ((%))
import Control.Monad
import Graphics.X11.Xlib.Extras
import Foreign.C.Types (CLong)
main = do
xmproc <- spawnPipe "/usr/bin/xmobar ~/.xmonad/xmobar.conf"
xmonad $ defaultConfig
{ modMask = mod4Mask
-- hooks, layouts
, layoutHook = myLayouts
, manageHook = myManageHook
, startupHook = setWMName "LG3D"
, logHook = dynamicLogWithPP $
xmobarPP
{ ppOutput = hPutStrLn xmproc
, ppTitle = xmobarColor "green" "" . shorten 80
}
} `additionalKeys`
[ ((0, xK_Print), spawn "ksnapshot")
, ((mod1Mask, xK_F4), kill)
, ((mod1Mask, xK_F2), spawn "exe=`dmenu_path | dmenu `&& eval \"exec $exe\"")
-- Move focus to the next window
, ((mod1Mask, xK_Tab ), windows W.focusDown)
]
myWorkspaces = ["1:im", "2:files", "3:web", "4:emacs"]
++ map show [5 .. 9]
genericLayouts = avoidStruts $
smartBorders $
toggleLayouts (noBorders Full) $
tiled ||| Mirror tiled ||| (noBorders Full)
where
tiled = Tall 1 (3 / 100) (1 / 2)
myLayouts = onWorkspaces ["1","8","9"] imLayout $
onWorkspaces ["4","5"] gimpLayout $
genericLayouts
myManageHook = mymyManageHook <+> manageMenus <+> manageDialogs
-- Float all menus and dialogs
manageMenus = checkMenu --> doFloat
manageDialogs = checkDialog --> doFloat
-- Check if window is a menu or dialog
checkMenu = checkAtom "_NET_WM_WINDOW_TYPE" "_NET_WM_WINDOW_TYPE_MENU"
checkDialog = checkAtom "_NET_WM_WINDOW_TYPE" "_NET_WM_WINDOW_TYPE_DIALOG"
first = ["psi"]
second = ["Krusader"]
third = ["Firefox", "Opera"]
fourth = ["Qmpdclient"]
ninth = ["Ktorrent"]
toAll = ["trayer","Kkbswitch"]
myIgnores = ["trayer"]
myFloats = ["Mplayer", "Yakuake", "Kmix", "Kkbswitch","gimp-dock"]
myCntrFloats = ["Smplayer", "dmenu", "glxgears", "Toplevel","Kio_uiserver"]
kkb = ["Индикатор раскладки"]
kkbpos = W.RationalRect 0.9 0.002 0.015 0.015
wmrole = stringProperty "WM_WINDOW_ROLE"
mymyManageHook = composeAll . concat $
[ [ className =? c --> doF (W.shift "1") | c <- first]
, [ className =? c --> doF (W.shift "2") | c <- second]
, [ className =? c --> doF (W.shift "3") | c <- third]
, [ className =? c --> doF (W.shift "4") | c <- fourth]
, [ className =? c --> doF (W.shift "9") | c <- ninth]
, [ className =? c --> doF (copyToAll) | c <- toAll]
, [ className =? c --> doFloat | c <- myFloats]
, [ wmrole =? r --> doFloat | r <- myFloats]
, [ className =? c --> doCenterFloat | c <- myCntrFloats]
, [ className =? c --> doIgnore | c <- myIgnores]
, [ title =? t --> doRectFloat kkbpos | t <- kkb]
, [ composeOne [ isFullscreen -?> doFullFloat, transience]]
]
imLayout = avoidStruts $ withIMs ratio rosters chatLayout where
chatLayout = Grid
ratio = 1%7
rosters = [skypeRoster, pidginRoster, psiRoaster]
pidginRoster = And (ClassName "Pidgin") (Title "Buddy List")
skypeRoster = (ClassName "Skype") `And`
(Not (Title "Options")) `And`
(Not (Role "Chats")) `And`
(Not (Role "CallWindowForm"))
psiRoaster = And (Resource "main") (ClassName "psi")
gimpLayout = avoidStruts $ withIMs ratio tools toolsLayout where
toolsLayout = Grid
ratio = 1%5
tools = [toolbox]
-- dock = (Role "gimp-dock")
toolbox = (Role "gimp-toolbox")
------------------------------------------------------------------------------------------
-- CODE, CODE, CODE --
-- Check if window has named atom with given value
checkAtom name value = ask >>= \w -> liftX $ do
a <- getAtom name
val <- getAtom value
mbr <- getProp a w
case mbr of
Just [r] -> return $ elem (fromIntegral r) [val]
_ -> return False
-- | Helper to read a property
getProp :: Atom -> Window -> X (Maybe [CLong])
getProp a w = withDisplay $ \dpy -> io $ getWindowProperty32 dpy a w
-- modified version of XMonad.Layout.IM --
-- | Data type for LayoutModifier which converts given layout to IM-layout
-- (with dedicated space for the roster and original layout for chat windows)
data AddRosters a = AddRosters Rational [Property] deriving (Read, Show)
instance LayoutModifier AddRosters Window where
modifyLayout (AddRosters ratio props) = applyIMs ratio props
modifierDescription _ = "IMs"
-- | Modifier which converts given layout to IMs-layout (with dedicated
-- space for rosters and original layout for chat windows)
withIMs :: LayoutClass l a => Rational -> [Property] -> l a -> ModifiedLayout AddRosters l a
withIMs ratio props = ModifiedLayout $ AddRosters ratio props
-- | IM layout modifier applied to the Grid layout
gridIMs :: Rational -> [Property] -> ModifiedLayout AddRosters Grid a
gridIMs ratio props = withIMs ratio props Grid
hasAnyProperty :: [Property] -> Window -> X Bool
hasAnyProperty [] _ = return False
hasAnyProperty (p:ps) w = do
b <- hasProperty p w
if b then return True else hasAnyProperty ps w
-- | Internal function for placing the rosters specified by
-- the properties and running original layout for all chat windows
applyIMs :: (LayoutClass l Window) =>
Rational
-> [Property]
-> W.Workspace WorkspaceId (l Window) Window
-> Rectangle
-> X ([(Window, Rectangle)], Maybe (l Window))
applyIMs ratio props wksp rect = do
let stack = W.stack wksp
let ws = W.integrate' $ stack
rosters <- filterM (hasAnyProperty props) ws
let n = fromIntegral $ length rosters
let (rostersRect, chatsRect) = splitHorizontallyBy (n * ratio) rect
let rosterRects = splitHorizontally n rostersRect
let filteredStack = stack >>= W.filter (`notElem` rosters)
wrs <- runLayout (wksp {W.stack = filteredStack}) chatsRect
return ((zip rosters rosterRects) ++ fst wrs, snd wrs)