xmonad.hs (view raw)
1{-# OPTIONS_HADDOCK prune #-}
2{-# OPTIONS_GHC -Wno-deprecations #-}
3
4----------------------------------------------------------------------
5-- |
6-- Description : la-ninpre xmonad config
7-- Maintainer : la-ninpre
8--
9-- personal xmonad config. based heavily on distrotube's config.
10-- i've added some stuff and toki pona fonts
11--
12----------------------------------------------------------------------
13
14module Main where
15
16import System.Directory
17import System.IO (hPutStrLn)
18import System.Exit (exitSuccess)
19
20import Data.Char (isSpace, toUpper)
21import Data.Maybe (fromJust)
22import Data.Monoid
23import Data.Maybe (isJust)
24import Data.Tree
25import Data.List
26import qualified Data.Map as M
27
28import XMonad
29import qualified XMonad.StackSet as W
30
31import XMonad.Actions.CopyWindow (kill1)
32import XMonad.Actions.CycleWS ( Direction1D(..)
33 , moveTo
34 , shiftTo
35 , WSType(..)
36 , nextScreen
37 , prevScreen
38 )
39import XMonad.Actions.GridSelect
40import XMonad.Actions.MouseResize
41import XMonad.Actions.Promote
42import XMonad.Actions.RotSlaves (rotSlavesDown, rotAllDown)
43import XMonad.Actions.WindowGo (runOrRaise)
44import XMonad.Actions.WithAll (sinkAll, killAll)
45import qualified XMonad.Actions.Search as S
46
47import XMonad.Hooks.DynamicLog
48import XMonad.Hooks.EwmhDesktops
49import XMonad.Hooks.ManageDocks ( avoidStruts
50 , docksEventHook
51 , manageDocks
52 , ToggleStruts(..))
53import XMonad.Hooks.ManageHelpers (isFullscreen, doFullFloat)
54import XMonad.Hooks.ServerMode
55import XMonad.Hooks.SetWMName
56import XMonad.Hooks.WorkspaceHistory
57
58import XMonad.Layout.SimplestFloat
59import XMonad.Layout.ResizableTile
60import XMonad.Layout.Tabbed
61import XMonad.Layout.ThreeColumns
62import XMonad.Layout.Accordion
63import XMonad.Layout.LayoutModifier
64import XMonad.Layout.LimitWindows (limitWindows, increaseLimit, decreaseLimit)
65import XMonad.Layout.Magnifier
66import XMonad.Layout.MultiToggle (mkToggle, single, EOT(EOT), (??))
67import XMonad.Layout.MultiToggle.Instances (StdTransformers( NBFULL
68 , MIRROR
69 , NOBORDERS
70 ))
71import XMonad.Layout.NoBorders
72import XMonad.Layout.Renamed
73import XMonad.Layout.ShowWName
74import XMonad.Layout.Simplest
75import XMonad.Layout.Spacing
76import XMonad.Layout.SubLayouts
77import XMonad.Layout.WindowNavigation
78import qualified XMonad.Layout.BoringWindows as BW
79import XMonad.Layout.WindowArranger (windowArrange, WindowArrangerMsg(..))
80import qualified XMonad.Layout.ToggleLayouts as T ( toggleLayouts
81 , ToggleLayout(Toggle)
82 )
83import qualified XMonad.Layout.MultiToggle as MT (Toggle(..))
84
85import XMonad.Util.Dmenu
86import XMonad.Util.Loggers
87import XMonad.Util.EZConfig (additionalKeysP)
88import XMonad.Util.NamedScratchpad
89import XMonad.Util.Run (runProcessWithInput, safeSpawn, spawnPipe)
90import XMonad.Util.SpawnOnce
91import XMonad.Util.WorkspaceCompare
92
93import LaNinpreConfig
94
95-- * misc functions
96--
97-- | hides workspaces that have no windows
98myHiddenNoWindows :: WorkspaceId -> String
99myHiddenNoWindows = const ""
100
101mySuperscript :: Int -> String
102mySuperscript n = map ss $ show n
103 where ss c | c == '0' = '⁰'
104 | c == '1' = '¹'
105 | c == '2' = '²'
106 | c == '3' = '³'
107 | c == '4' = '⁴'
108 | c == '5' = '⁵'
109 | c == '6' = '⁶'
110 | c == '7' = '⁷'
111 | c == '8' = '⁸'
112 | c == '9' = '⁹'
113 | otherwise = c
114
115
116-- | window count logger
117--
118-- gets number of windows on current workspace
119myWindowCountLogger :: Logger
120myWindowCountLogger = gets $ Just . show . length . W.integrate' . W.stack
121 . W.workspace . W.current . windowset
122
123myTestLogger :: Logger
124myTestLogger = gets $ Just . xmobarColor (myColor "yellow") "" . intercalate " "
125 . \s -> ( let w = windowset $ s
126 ws = map W.workspace (W.current w : W.visible w) ++ W.hidden w
127 t = map (wrap "<fn=3>" "</fn>") . map W.tag $ ws
128 l = map length
129 . map W.integrate'
130 . map W.stack $ ws
131 in zipWith (++) t $ map mySuperscript l
132 )
133
134
135-- * grid select
136--
137-- $gridSelect
138--
139-- this section provides theming of @GridSelect@ stuff.
140--
141-- here, @GridSelect@ is used for following things:
142--
143-- * spawning some frequently used programs
144--
145-- * moving to desired window
146--
147-- * bringing the desired window to the current workspace
148
149-- | custom colorizer that colors windows based on their class
150myColorizer :: Window -> Bool -> X (String, String)
151myColorizer = colorRangeFromClassName
152 (0x00,0x00,0x00) -- lowest inactive bg
153 (0xbd,0x9c,0xf9) -- highest inactive bg
154 (0xc7,0x92,0xea) -- active bg
155 (0xc0,0xa7,0x9a) -- inactive fg
156 (0x28,0x2c,0x34) -- active fg
157
158-- | gridSelect config
159myGridConfig :: p -> GSConfig Window
160myGridConfig colorizer = (buildDefaultGSConfig myColorizer)
161 { gs_cellheight = 40
162 , gs_cellwidth = 200
163 , gs_cellpadding = 6
164 , gs_originFractX = 0.5
165 , gs_originFractY = 0.5
166 , gs_font = (myFonts !! 0)
167 }
168
169-- | spawn selected programs with grid select
170spawnSelected' :: [(String, String)] -> X ()
171spawnSelected' lst = gridselect conf lst >>= flip whenJust spawn
172 where conf = def
173 { gs_cellheight = 40
174 , gs_cellwidth = 200
175 , gs_cellpadding = 6
176 , gs_originFractX = 0.5
177 , gs_originFractY = 0.5
178 , gs_font = (myFonts !! 0)
179 }
180
181-- * layouts
182--
183-- ** spacing raw helper functions
184--
185-- $spacingHelpers
186--
187-- theese are making calls to spacingRaw simpler to write
188
189-- | for many windows
190mySpacing :: Integer -> l a -> XMonad.Layout.LayoutModifier.ModifiedLayout Spacing l a
191mySpacing i = spacingRaw False (Border i i i i) True (Border i i i i) True
192
193-- | for fewer than two windows
194mySpacing' :: Integer -> l a -> XMonad.Layout.LayoutModifier.ModifiedLayout Spacing l a
195mySpacing' i = spacingRaw True (Border i i i i) True (Border i i i i) True
196
197-- ** actually layouts
198--
199-- $layouts
200--
201-- currently there are:
202--
203-- * tall
204--
205-- * floats
206--
207-- * threeCol
208
209tall = renamed [Replace "tall"]
210 $ smartBorders
211 $ addTabs shrinkText myTabTheme
212 $ subLayout [] (smartBorders Simplest ||| Accordion)
213 $ limitWindows 12
214 $ mySpacing 4
215 $ ResizableTall 1 (5/100) (1/2) []
216
217floats = renamed [Replace "floats"]
218 $ smartBorders
219 $ limitWindows 20
220 $ simplestFloat
221
222threeCol = renamed [Replace "threeCol"]
223 $ smartBorders
224 $ addTabs shrinkText myTabTheme
225 $ subLayout [] (smartBorders Simplest ||| Accordion)
226 $ limitWindows 7
227 $ mySpacing 4
228 $ ThreeColMid 1 (3/100) (1/2)
229
230-- | setting colors for tabs layout and tabs sublayout.
231myTabTheme = def
232 { fontName = (myFonts !! 0)
233 , activeColor = myColor "gray4"
234 , inactiveColor = myColor "gray0"
235 , activeBorderColor = myColor "gray4"
236 , inactiveBorderColor = myColor "gray0"
237 , activeTextColor = myColor "bg"
238 , inactiveTextColor = myColor "fg"
239 }
240
241-- ** layout hook
242
243-- $layoutHook
244--
245-- putting it all together with some stuff
246myLayoutHook = avoidStruts
247 $ mouseResize
248 $ BW.boringWindows
249 $ windowNavigation
250 $ windowArrange
251 $ T.toggleLayouts floats
252 $ mkToggle (NBFULL ?? NOBORDERS ?? EOT) myDefaultLayout
253 where
254 myDefaultLayout = withBorder myBorderWidth tall
255 ||| withBorder myBorderWidth threeCol
256
257-- * show wm name hook
258
259-- | theme for showWName which prints current workspace
260-- when you change workspaces.
261myShowWNameTheme :: SWNConfig
262myShowWNameTheme = def
263 { swn_font = (myFonts !! 1)
264 , swn_fade = 0.7
265 , swn_bgcolor = myColor "bg"
266 , swn_color = myColor "fg"
267 }
268
269-- * workspaces
270--
271-- $workspaces
272--
273-- here are some helper functions to deal with workspaces.
274--
275-- actual workspace list is in "LaNinpreConfig".
276
277-- | workspace indices to use with hotkeys
278myWorkspaceIndices = M.fromList $ zipWith (,) myWorkspaces [1..]
279
280-- ** clickable workspace wrapper
281--
282-- $clickable
283--
284-- normal variant
285--
286-- > clickable ws = "<action=xdotool key super+"++show i++">"++ws++"</action>"
287-- > where i = fromJust $ M.lookup ws myWorkspaceIndices
288
289-- | provides option to click workspaces to switch to them.
290-- this is handled by @UnsafeStdinReader@ in xmobar config.
291clickable ws = "<fn=3><action=xdotool key super+"++show i++">"++ws++"</action></fn>"
292 where i = fromJust $ M.lookup ws myWorkspaceIndices
293
294-- * keybindings
295
296-- | keybindings list
297--
298-- there's no way to document it using haddock, i guess...
299myKeys :: [(String, X ())]
300myKeys =
301 [ ("M-C-r", spawn "xmonad --recompile") -- Recompiles xmonad
302 , ("M-S-r", spawn "xmonad --restart") -- Restarts xmonad
303 , ("M-S-q", io exitSuccess) -- Quits xmonad
304
305 -- Run Prompt
306 , ("M-r", spawn "dmenu_run -i -p \"Run: \"") -- Dmenu
307
308 -- Other Dmenu Prompts
309 -- In Xmonad and many tiling window managers, M-p is the default keybinding to
310 -- launch dmenu_run, so I've decided to use M-p plus KEY for these dmenu scripts.
311 , ("M-p p", spawn "passmenu") -- passmenu
312 , ("M-p c", spawn "dm-colpick") -- pick color from our scheme
313 , ("M-p e", spawn "dm-confedit") -- edit config files
314 , ("M-p i", spawn "dm-maim") -- screenshots (images)
315 , ("M-p k", spawn "dm-kill") -- kill processes
316 , ("M-p m", spawn "dm-man") -- manpages
317 , ("M-p q", spawn "dm-logout") -- logout menu
318 , ("M-p s", spawn "dm-websearch") -- search various search engines
319 , ("M-p h", spawn "dm-hub") -- hub of all scripts to choose one
320
321 -- Useful programs to have a keybinding for launch
322 , ("M-<Return>", spawn (myTerminal))
323 , ("M-e", spawn (myFileMgr))
324 , ("M-w", spawn (myBrowser))
325 , ("M-i", spawn (myTerminal
326 ++ " --class alacritty,amfora -e "
327 ++ myGeminiClient))
328 , ("M-S-e", spawn "emacsclient -c")
329 -- Kill windows
330 , ("M-S-c", kill1) -- Kill the currently focused client
331 , ("M-S-a", killAll) -- Kill all windows on current workspace
332
333 -- Workspaces
334 , ("M-.", nextScreen) -- Switch focus to next monitor
335 , ("M-,", prevScreen) -- Switch focus to prev monitor
336 -- Shifts focused window to next ws
337 , ("M-S-<KP_Add>", shiftTo Next nonNSP >> moveTo Next nonNSP)
338 -- Shifts focused window to prev ws
339 , ("M-S-<KP_Subtract>", shiftTo Prev nonNSP >> moveTo Prev nonNSP)
340
341 -- Floating windows
342 , ("M-f", sendMessage (T.Toggle "floats")) -- Toggles my 'floats' layout
343 , ("M-t", withFocused $ windows . W.sink) -- Push floating window back to tile
344 , ("M-S-t", sinkAll) -- Push ALL floating windows to tile
345
346 -- Increase/decrease spacing (gaps)
347 , ("C-M1-j", decWindowSpacing 4) -- Decrease window spacing
348 , ("C-M1-k", incWindowSpacing 4) -- Increase window spacing
349 , ("C-M1-h", decScreenSpacing 4) -- Decrease screen spacing
350 , ("C-M1-l", incScreenSpacing 4) -- Increase screen spacing
351
352 -- Grid Select (MOD-g followed by a key)
353 , ("M-g g", spawnSelected' myAppGrid) -- grid select favorite apps
354 , ("M-g t", goToSelected $ myGridConfig myColorizer) -- goto selected window
355 , ("M-g b", bringSelected $ myGridConfig myColorizer) -- bring selected window
356
357 -- Windows navigation
358 , ("M-m", windows W.focusMaster) -- Move focus to the master window
359 , ("M-j", BW.focusDown) -- Move focus to the next window
360 , ("M1-<Tab>", BW.focusDown) -- legacy keybinding
361 , ("M-k", BW.focusUp) -- Move focus to the prev window
362 , ("M-S-m", windows W.swapMaster) -- Swap the focused window and the master window
363 , ("M-S-j", windows W.swapDown) -- Swap focused window with next window
364 , ("M-S-k", windows W.swapUp) -- Swap focused window with prev window
365 , ("M-<Backspace>", promote) -- Moves focused window to master, others maintain order
366 , ("M-S-<Tab>", rotSlavesDown) -- Rotate all windows except master and keep focus in place
367 , ("M-C-<Tab>", rotAllDown) -- Rotate all the windows in the current stack
368
369 -- Layouts
370 , ("M-<Tab>", sendMessage NextLayout) -- Switch to next layout
371 , ("M-b", sendMessage (MT.Toggle NBFULL))
372 , ("M-<Space>", sendMessage (MT.Toggle NBFULL) >> sendMessage ToggleStruts) -- Toggles noborder/full
373
374 -- Increase/decrease windows in the master pane or the stack
375 , ("M-S-<Up>", sendMessage (IncMasterN 1)) -- Increase # of clients master pane
376 , ("M-S-<Down>", sendMessage (IncMasterN (-1))) -- Decrease # of clients master pane
377 , ("M-C-<Up>", increaseLimit) -- Increase # of windows
378 , ("M-C-<Down>", decreaseLimit) -- Decrease # of windows
379
380 -- Window resizing
381 , ("M-h", sendMessage Shrink) -- Shrink horiz window width
382 , ("M-l", sendMessage Expand) -- Expand horiz window width
383 , ("M-M1-j", sendMessage MirrorShrink) -- Shrink vert window width
384 , ("M-M1-k", sendMessage MirrorExpand) -- Expand vert window width
385
386 -- Sublayouts
387 -- This is used to push windows to tabbed sublayouts, or pull them out of it.
388 , ("M-C-h", sendMessage $ pullGroup L)
389 , ("M-C-l", sendMessage $ pullGroup R)
390 , ("M-C-k", sendMessage $ pullGroup U)
391 , ("M-C-j", sendMessage $ pullGroup D)
392 , ("M-C-m", withFocused (sendMessage . MergeAll))
393 , ("M-C-u", withFocused (sendMessage . UnMerge))
394 , ("M-C-/", withFocused (sendMessage . UnMergeAll))
395 , ("M-C-<Space>", toSubl NextLayout)
396 , ("M-C-.", onGroup W.focusUp') -- Switch focus to next tab
397 , ("M-C-,", onGroup W.focusDown') -- Switch focus to prev tab
398
399 -- Scratchpads
400 -- Toggle show/hide these programs. They run on a hidden workspace.
401 -- When you toggle them to show, it brings them to your current workspace.
402 -- Toggle them to hide and it sends them back to hidden workspace (NSP).
403 , ("M-s t", namedScratchpadAction myScratchPads "terminal")
404 , ("M-s m", namedScratchpadAction myScratchPads "mocp")
405 , ("M-s c", namedScratchpadAction myScratchPads "calculator")
406 , ("M-s v", namedScratchpadAction myScratchPads "mpvfloat" )
407
408 -- Set wallpaper with 'feh'. Type 'SUPER+F1' to launch sxiv in the wallpapers directory.
409 -- Then in sxiv, type 'C-x w' to set the wallpaper that you choose.
410 , ("M-<F1>", spawn "sxiv -r -q -t -o ~/Pictures/wallpapers/*")
411 , ("M-<F2>", spawn "/bin/ls ~/Pictures/wallpapers | shuf -n 1 \
412 \| xargs xwallpaper --stretch")
413
414 -- pana e nimi sewi
415 , ("M-<F7>", spawn "nimi_sewi")
416
417 -- Controls for mocp music player (SUPER-u followed by a key)
418 , ("M-u p", spawn (myMocp ++ " --play"))
419 , ("M-u l", spawn (myMocp ++ " --next"))
420 , ("M-u h", spawn (myMocp ++ " --previous"))
421 , ("M-u <Space>", spawn (myMocp ++ " --toggle-pause"))
422
423 -- Multimedia Keys
424 , ("<XF86AudioPlay>", spawn (myMocp ++ " --toggle-pause"))
425 , ("<XF86AudioPrev>", spawn (myMocp ++ " --previous"))
426 , ("<XF86AudioNext>", spawn (myMocp ++ " --next"))
427 , ("<XF86AudioMute>", spawn (myMocp ++ " -v 0"))
428 , ("<XF86AudioLowerVolume>", spawn (myMocp ++ " -v -1"))
429 , ("<XF86AudioRaiseVolume>", spawn (myMocp ++ " -v +1"))
430 , ("<XF86HomePage>", spawn "brave https://aaoth.xyz")
431 , ("<XF86Search>", spawn "dm-websearch")
432 , ("<XF86Mail>", runOrRaise "geary" (resource =? "geary"))
433 , ("<XF86Calculator>", namedScratchpadAction myScratchPads "calculator")
434 , ("<XF86Sleep>", spawn "dm-logout")
435 ]
436 -- the following lines are needed for named scratchpads.
437 where nonNSP = WSIs (return (\ws -> W.tag ws /= "NSP"))
438 nonEmptyNonNSP = WSIs (return (\ws -> isJust (W.stack ws)
439 && W.tag ws /= "NSP"))
440
441
442main :: IO ()
443main = do
444 xmproc <- spawnPipe "xmobar ~/.xmonad/xmobar/xmobarrc"
445 -- the xmonad, ya know...what the wm is named after!
446 xmonad $ ewmh def
447 { manageHook = myManageHook <+> manageDocks
448 , handleEventHook = docksEventHook
449 , modMask = myModMask
450 , terminal = myTerminal
451 , startupHook = myStartupHook
452 , layoutHook = showWName' myShowWNameTheme $ myLayoutHook
453 , workspaces = myWorkspaces
454 , borderWidth = myBorderWidth
455 , normalBorderColor = myNormColor
456 , focusedBorderColor = myFocusColor
457 , logHook = dynamicLogWithPP
458 $ namedScratchpadFilterOutWorkspacePP
459 $ xmobarPP
460 { ppOutput = hPutStrLn xmproc
461 , ppCurrent = xmobarColor (myColor "green-bright") ""
462 . wrap "<fn=3>" "</fn>" -- toki pona
463 . wrap "[" "]"
464 -- . wrap " " " " -- normal
465 , ppVisible = xmobarColor (myColor "green-bright") "" . clickable
466 , ppHidden = xmobarColor (myColor "blue-bright") ""
467 . wrap "" "'"
468 . clickable
469 , ppHiddenNoWindows = xmobarColor (myColor "gray2") "" . clickable
470 --, ppHiddenNoWindows = myHiddenNoWindows
471 , ppTitle = xmobarColor (myColor "gray4") "" . shorten 60
472 , ppSep = xmobarColor (myColor "gray3") "" " | "
473 , ppWsSep = " "
474 , ppUrgent = xmobarColor (myColor "yellow") "" . wrap "!" "!"
475 , ppExtras = [myWindowCountLogger]
476 , ppOrder = \(ws:l:t:ex) -> [ws,l]++ex++[t]
477 }
478 } `additionalKeysP` myKeys
479