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