geekosaur's xmonad.hs (2015-07-22 iteration)

geekosaur 2015-07-22 15:31:32.230791 UTC

1{-# LANGUAGE OverloadedStrings #-}
2
3import XMonad
4import XMonad.Actions.CopyWindow
5import XMonad.Actions.SpawnOn
6-- import XMonad.Config.Desktop
7import XMonad.Config.Mate
8-- import XMonad.Hooks.DebugEvents
9import XMonad.Hooks.DynamicLog
10import XMonad.Hooks.EwmhDesktops
11import XMonad.Hooks.ManageDebug
12import XMonad.Hooks.ManageDocks
13import XMonad.Hooks.ManageHelpers
14import XMonad.Hooks.Minimize
15import XMonad.Hooks.Place
16import XMonad.Layout.Accordion
17import XMonad.Layout.DragPane
18import XMonad.Layout.GridVariants
19import XMonad.Layout.IM
20import XMonad.Layout.Maximize
21import XMonad.Layout.Minimize
22import XMonad.Layout.NoBorders
23import XMonad.Layout.OneBig
24import XMonad.Layout.PerWorkspace
25import XMonad.Layout.Renamed
26import XMonad.Layout.StackTile
27import XMonad.Layout.Tabbed
28import XMonad.Layout.TwoPane
29import XMonad.Util.NamedScratchpad
30import XMonad.Util.EZConfig
31import qualified XMonad.StackSet as W
32
33import qualified Codec.Binary.UTF8.String as UTF8
34import Control.Monad (when)
35import Data.Monoid
36import qualified DBus as D
37import qualified DBus.Client as D
38import System.Environment (getArgs)
39import System.Posix.Env (putEnv)
40import System.Posix.IO
41import Control.Concurrent (threadDelay)
42import Numeric (showHex)
43
44-- baseConfig = mateConfig
45baseConfig = debugManageHookOn "M-C-d" mateConfig
46
47scratchpads = [NS "notes"
48 "leafpad --name=notes ~/Documents/Notepad.txt"
49 (appName =? "notes")
50 (setUtility <+> noTaskBar <+> customFloating (W.RationalRect 0.4 0.35 0.2 0.3))
51 ,NS "timelog"
52 "leafpad --name=timelog ~/Documents/Timelog.txt"
53 (appName =? "timelog")
54 (setUtility <+> noTaskBar <+> customFloating (W.RationalRect 0.1 0.1 0.2 0.3))
55 ,NS "notes3"
56 "leafpad --name=notes3 ~/Documents/Notepad3.txt"
57 (appName =? "notes3")
58 (setUtility <+> noTaskBar <+> customFloating (W.RationalRect 0.7 0.1 0.2 0.3))
59 ,NS "notes4"
60 "leafpad --name=notes4 ~/Documents/Notepad4.txt"
61 (appName =? "notes4")
62 (setUtility <+> noTaskBar <+> customFloating (W.RationalRect 0.1 0.7 0.2 0.3))
63 ,NS "notes5"
64 "leafpad --name=notes5 ~/Documents/Notepad5.txt"
65 (appName =? "notes5")
66 (setUtility <+> noTaskBar <+> customFloating (W.RationalRect 0.7 0.7 0.2 0.3))
67 ,NS "calc"
68 -- @@@ perhaps assign a specific name or role for this
69 "mate-calc"
70 (appName =? "mate-calc")
71 (setUtility <+> noTaskBar <+> doFloatAt 0.78 0.1)
72 ,NS "charmap"
73 "gucharmap"
74 (appName =? "gucharmap")
75 (setUtility <+> noTaskBar <+> doFloatPlace)
76 ,NS "crawl"
77 "xfce4-terminal --disable-server --hide-toolbar --hide-menubar --role=crawl --title=Crawl -e $HOME/.bin/crawloop"
78 (appName =? "xfce4-terminal" <&&> role =? "crawl")
79 -- @@@ fails, terminal bug? 23x79
80 -- @@@@ or does the core not account for the border, which is *inside* the window?
81 -- (doFloatAt 0.52 0.1)
82 -- @@@ BEWARE this is jiggered to be 80x24
83 (noTaskBar <+> customFloating (W.RationalRect 0.52 0.1 0.43 0.43))
84 ,NS "mtr"
85 "mate-terminal --disable-factory --hide-menubar --name=mtr --title=mtr -x sudo mtr --curses dreamshell.ttuttle.net"
86 (appName =? "mtr")
87 (setUtility <+> noTaskBar <+> customFloating (W.RationalRect 0 0 1 0.55))
88 ]
89
90workspacen :: [String]
91workspacen = ["emacs", "irc", "mail", "chrome", "openafs", "finance", "pending", "games", "tv", "calibre", "misc", "spare"]
92
93main = do
94 -- something is undoing this. regularly.
95 -- make shift-space = space
96 -- swap mouse buttons 4 and 5 (scroll direction) since MATE lacks a way to do it
97 -- @@@ note need to reset to default, else it toggles...
98 spawn "xmodmap -e 'keycode 65 = space space space space NoSymbol NoSymbol thinspace nobreakspace' \
99 \ -e 'pointer = default' \
100 \ -e 'pointer = 1 2 3 5 4 6 7 8 9 10 11 12 13'"
101 -- openjdk hackaround
102 putEnv "_JAVA_AWT_WM_NONREPARENTING=1"
103 -- xmonad log applet
104 dbus <- D.connectSession
105 getWellKnownName dbus
106 -- do it to it
107 xmonad $ baseConfig
108 {modMask = mod4Mask
109 ,workspaces = workspacen
110 ,borderWidth = 2
111 ,focusedBorderColor= "#F57900" -- @@ from MATE theme
112 ,normalBorderColor = "#888A85"
113 ,focusFollowsMouse = False
114 ,clickJustFocuses = False
115 ,layoutHook = renamed [CutWordsLeft 2] $
116 minimize $
117 maximize $
118 avoidStruts $
119 lessBorders Screen $
120 onWorkspace "irc" (withIM 0.125 (Resource "Pidgin" `And` Role "buddy_list") ims) $
121 onWorkspace "calibre" (noBorders Full) $
122 onWorkspace "games" (noBorders Full) $
123 TwoPane 0.03 0.5 |||
124 dragPane Horizontal 0.03 0.5 |||
125 Accordion |||
126 simpleTabbed |||
127 Full
128 ,manageHook = composeAll
129 [appName =? "Pidgin" --> doShift "irc"
130 ,appName =? "xmessage" --> doFloatPlace
131 ,isInProperty "_NET_WM_STATE" "_NET_WM_STATE_STICKY" --> doIgnore
132 -- ,appName =? "Pidgin" <&&> role =? "conversation" --> boing "phone-incoming-call"
133 ,manageSpawn
134 ,namedScratchpadManageHook scratchpads
135 ,placeHook myPlaceHook
136 ,isDialog --> doFloatPlace
137 ,manageHook baseConfig
138 ]
139 ,logHook = logTitle dbus <+> logHook baseConfig
140 ,handleEventHook = debuggering <+>
141 fullscreenEventHook <+>
142 minimizeEventHook <+>
143 handleEventHook baseConfig
144 ,startupHook = do
145 startupHook baseConfig
146 as <- io getArgs
147 when (null as) $ do
148 spawn "compton -cCfGb --backend=glx"
149{-
150 -- @@@ hacky workaround for panel bug triggered by vmware tools/open-vm-tools:
151 -- let screen resize, restart panel, let it settle
152 io $ threadDelay 10000000
153 spawn "mate-panel --replace"
154-}
155 io $ threadDelay 2500000
156 -- @@@ starts multi windows, placing them automatically will not fly :/
157 -- spawnOn "mail" spawnChrome
158 spawnOn "irc" "pidgin"
159 spawnOn "emacs" "mate-terminal"
160 spawnOn "emacs" "emacs"
161 -- hack: ewmh props don't get set until something forces logHook, so...
162 asks (logHook . config) >>= id
163 }
164 `additionalKeysP`
165 ([("M-C-n", namedScratchpadAction scratchpads "notes")
166 ,("M-C-t", namedScratchpadAction scratchpads "timelog")
167 ,("M-C-3", namedScratchpadAction scratchpads "notes3")
168 ,("M-C-4", namedScratchpadAction scratchpads "notes4")
169 ,("M-C-5", namedScratchpadAction scratchpads "notes5")
170 ,("M-C-c", namedScratchpadAction scratchpads "crawl")
171 ,("C-`", namedScratchpadAction scratchpads "mtr")
172 ,("M-C-k", namedScratchpadAction scratchpads "calc")
173 ,("M-C-m", namedScratchpadAction scratchpads "charmap")
174 ,("M-C-e", spawn spawnEvernote)
175 ,("M-C-g", spawn spawnChrome)
176 ,("M-S-=", withFocused $ sendMessage . maximizeRestore)
177 -- multiple-screen shot
178 ,("M-S-s", spawn "sleep 0.1; scrot -m 'Downloads/screenshot-%Y%m%dT%H%M%S.png'")
179 -- select window shot
180 ,("M-S-w", spawn "sleep 0.1; scrot -s 'Downloads/screenshot-%Y%m%dT%H%M%S.png'")
181 -- debug window
182 ,("M-C-S-7", spawn "xprop | xmessage -file -")
183 ,("M-C-S-6", withFocused $ \w -> spawn $ "xprop -id 0x" ++ showHex w "" ++ " | xmessage -file -")
184 ,("M-C-S-5", withFocused $ \w -> spawn $ "xwininfo -id 0x" ++ showHex w "" ++ " -all | xmessage -file -")
185 ]
186 ++
187 -- greedyView -> view, so I stop breaking crawl etc. >.>
188 [(otherModMasks ++ "M-" ++ [key], action tag)
189 | (tag, key) <- zip workspacen "1234567890-="
190 , (otherModMasks, action) <- [("", windows . W.view) -- was W.greedyView
191 ,("S-", windows . W.shift)
192 ]
193 ])
194
195spawnEvernote = "wine ~/'.wine/drive_c/Program Files (x86)/Evernote/Evernote/Evernote.exe' >/dev/null 2>&1"
196spawnChrome = "google-chrome --allow-file-access-from-files"
197
198myPlaceHook = inBounds $ smart (0.5, 0.5)
199
200doFloatPlace :: ManageHook
201doFloatPlace = placeHook myPlaceHook <+> doFloat
202
203ims = renamed [CutWordsRight 2] $
204 OneBig (4/5) (3/4) |||
205 StackTile 1 (3/100) (1/2) |||
206 TwoPane 0.03 0.5 |||
207 Grid 0.2 |||
208 Accordion |||
209 Full
210
211role :: Query String
212role = stringProperty "WM_WINDOW_ROLE"
213
214-- haaaaaack
215noTaskBar :: ManageHook
216noTaskBar = ask >>= (>> idHook) . liftX . markNoTaskBar
217
218markNoTaskBar :: Window -> X ()
219markNoTaskBar w = withDisplay $ \d -> do
220 ws <- getAtom "_NET_WM_STATE"
221 ntb <- getAtom "_NET_WM_STATE_SKIP_TASKBAR"
222 npg <- getAtom "_NET_WM_STATE_SKIP_PAGER"
223 wst' <- io $ getWindowProperty32 d ws w
224 -- @@@ possibly this could just be Prepend...
225 let wst = case wst' of
226 Nothing -> [fi ntb,fi npg]
227 Just s -> fi ntb:fi npg:s
228 io $ changeProperty32 d w ws aTOM propModeReplace wst
229
230setUtility :: ManageHook
231setUtility = ask >>= (>> idHook) . liftX . markUtility
232
233markUtility :: Window -> X ()
234markUtility w = withDisplay $ \d -> do
235 wt <- getAtom "_NET_WM_WINDOW_TYPE"
236 wtu <- getAtom "_NET_WM_WINDOW_TYPE_UTILITY"
237 io $ changeProperty32 d w wt aTOM propModeReplace [fi wtu]
238
239-- sigh
240fi :: (Integral i, Num n) => i -> n
241fi = fromIntegral
242
243logTitle :: D.Client -> X ()
244logTitle ch = dynamicLogWithPP defaultPP
245 {ppOrder = \(_:l:t:_) -> [l,t]
246 ,ppSep = "⋮"
247 ,ppOutput = dbusOutput ch
248 }
249
250getWellKnownName :: D.Client -> IO ()
251getWellKnownName ch = do
252 D.requestName ch (D.busName_ "org.xmonad.Log")
253 [D.nameAllowReplacement, D.nameReplaceExisting, D.nameDoNotQueue]
254 return ()
255
256dbusOutput :: D.Client -> String -> IO ()
257dbusOutput ch s = do
258 let sig = (D.signal "/org/xmonad/Log" "org.xmonad.Log" "Update")
259 {D.signalBody = [D.toVariant (UTF8.decodeString s)]}
260 D.emit ch sig
261
262boing :: String -> Query ()
263boing snd = liftX $ spawn $ "paplay /usr/share/sounds/freedesktop/stereo/" ++ snd ++ ".oga"
264
265debuggering :: Event -> X All
266-- debuggering = debugEventsHook
267debuggering = idHook