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 -- Kill windows
327 , ("M-S-c", kill1) -- Kill the currently focused client
328 , ("M-S-a", killAll) -- Kill all windows on current workspace
329
330 -- Workspaces
331 , ("M-.", nextScreen) -- Switch focus to next monitor
332 , ("M-,", prevScreen) -- Switch focus to prev monitor
333 -- Shifts focused window to next ws
334 , ("M-S-<KP_Add>", shiftTo Next nonNSP >> moveTo Next nonNSP)
335 -- Shifts focused window to prev ws
336 , ("M-S-<KP_Subtract>", shiftTo Prev nonNSP >> moveTo Prev nonNSP)
337
338 -- Floating windows
339 , ("M-f", sendMessage (T.Toggle "floats")) -- Toggles my 'floats' layout
340 , ("M-t", withFocused $ windows . W.sink) -- Push floating window back to tile
341 , ("M-S-t", sinkAll) -- Push ALL floating windows to tile
342
343 -- Increase/decrease spacing (gaps)
344 , ("C-M1-j", decWindowSpacing 4) -- Decrease window spacing
345 , ("C-M1-k", incWindowSpacing 4) -- Increase window spacing
346 , ("C-M1-h", decScreenSpacing 4) -- Decrease screen spacing
347 , ("C-M1-l", incScreenSpacing 4) -- Increase screen spacing
348
349 -- Grid Select (MOD-g followed by a key)
350 , ("M-g g", spawnSelected' myAppGrid) -- grid select favorite apps
351 , ("M-g t", goToSelected $ myGridConfig myColorizer) -- goto selected window
352 , ("M-g b", bringSelected $ myGridConfig myColorizer) -- bring selected window
353
354 -- Windows navigation
355 , ("M-m", windows W.focusMaster) -- Move focus to the master window
356 , ("M-j", BW.focusDown) -- Move focus to the next window
357 , ("M1-<Tab>", BW.focusDown) -- legacy keybinding
358 , ("M-k", BW.focusUp) -- Move focus to the prev window
359 , ("M-S-m", windows W.swapMaster) -- Swap the focused window and the master window
360 , ("M-S-j", windows W.swapDown) -- Swap focused window with next window
361 , ("M-S-k", windows W.swapUp) -- Swap focused window with prev window
362 , ("M-<Backspace>", promote) -- Moves focused window to master, others maintain order
363 , ("M-S-<Tab>", rotSlavesDown) -- Rotate all windows except master and keep focus in place
364 , ("M-C-<Tab>", rotAllDown) -- Rotate all the windows in the current stack
365
366 -- Layouts
367 , ("M-<Tab>", sendMessage NextLayout) -- Switch to next layout
368 , ("M-b", sendMessage (MT.Toggle NBFULL))
369 , ("M-<Space>", sendMessage (MT.Toggle NBFULL) >> sendMessage ToggleStruts) -- Toggles noborder/full
370
371 -- Increase/decrease windows in the master pane or the stack
372 , ("M-S-<Up>", sendMessage (IncMasterN 1)) -- Increase # of clients master pane
373 , ("M-S-<Down>", sendMessage (IncMasterN (-1))) -- Decrease # of clients master pane
374 , ("M-C-<Up>", increaseLimit) -- Increase # of windows
375 , ("M-C-<Down>", decreaseLimit) -- Decrease # of windows
376
377 -- Window resizing
378 , ("M-h", sendMessage Shrink) -- Shrink horiz window width
379 , ("M-l", sendMessage Expand) -- Expand horiz window width
380 , ("M-M1-j", sendMessage MirrorShrink) -- Shrink vert window width
381 , ("M-M1-k", sendMessage MirrorExpand) -- Expand vert window width
382
383 -- Sublayouts
384 -- This is used to push windows to tabbed sublayouts, or pull them out of it.
385 , ("M-C-h", sendMessage $ pullGroup L)
386 , ("M-C-l", sendMessage $ pullGroup R)
387 , ("M-C-k", sendMessage $ pullGroup U)
388 , ("M-C-j", sendMessage $ pullGroup D)
389 , ("M-C-m", withFocused (sendMessage . MergeAll))
390 , ("M-C-u", withFocused (sendMessage . UnMerge))
391 , ("M-C-/", withFocused (sendMessage . UnMergeAll))
392 , ("M-C-<Space>", toSubl NextLayout)
393 , ("M-C-.", onGroup W.focusUp') -- Switch focus to next tab
394 , ("M-C-,", onGroup W.focusDown') -- Switch focus to prev tab
395
396 -- Scratchpads
397 -- Toggle show/hide these programs. They run on a hidden workspace.
398 -- When you toggle them to show, it brings them to your current workspace.
399 -- Toggle them to hide and it sends them back to hidden workspace (NSP).
400 , ("M-s t", namedScratchpadAction myScratchPads "terminal")
401 , ("M-s m", namedScratchpadAction myScratchPads "mocp")
402 , ("M-s c", namedScratchpadAction myScratchPads "calculator")
403 , ("M-s v", namedScratchpadAction myScratchPads "mpvfloat" )
404
405 -- Set wallpaper with 'feh'. Type 'SUPER+F1' to launch sxiv in the wallpapers directory.
406 -- Then in sxiv, type 'C-x w' to set the wallpaper that you choose.
407 , ("M-<F1>", spawn "sxiv -r -q -t -o ~/Pictures/wallpapers/*")
408 , ("M-<F2>", spawn "/bin/ls ~/Pictures/wallpapers | shuf -n 1 \
409 \| xargs xwallpaper --stretch")
410
411 -- pana e nimi sewi
412 , ("M-<F7>", spawn "nimi_sewi")
413
414 -- Controls for mocp music player (SUPER-u followed by a key)
415 , ("M-u p", spawn (myMocp ++ " --play"))
416 , ("M-u l", spawn (myMocp ++ " --next"))
417 , ("M-u h", spawn (myMocp ++ " --previous"))
418 , ("M-u <Space>", spawn (myMocp ++ " --toggle-pause"))
419
420 -- Multimedia Keys
421 , ("<XF86AudioPlay>", spawn (myMocp ++ " --toggle-pause"))
422 , ("<XF86AudioPrev>", spawn (myMocp ++ " --previous"))
423 , ("<XF86AudioNext>", spawn (myMocp ++ " --next"))
424 , ("<XF86AudioMute>", spawn (myMocp ++ " -v 0"))
425 , ("<XF86AudioLowerVolume>", spawn (myMocp ++ " -v -1"))
426 , ("<XF86AudioRaiseVolume>", spawn (myMocp ++ " -v +1"))
427 , ("<XF86HomePage>", spawn "brave https://aaoth.xyz")
428 , ("<XF86Search>", spawn "dm-websearch")
429 , ("<XF86Mail>", runOrRaise "geary" (resource =? "geary"))
430 , ("<XF86Calculator>", namedScratchpadAction myScratchPads "calculator")
431 , ("<XF86Sleep>", spawn "dm-logout")
432 ]
433 -- the following lines are needed for named scratchpads.
434 where nonNSP = WSIs (return (\ws -> W.tag ws /= "NSP"))
435 nonEmptyNonNSP = WSIs (return (\ws -> isJust (W.stack ws)
436 && W.tag ws /= "NSP"))
437
438
439main :: IO ()
440main = do
441 xmproc <- spawnPipe "xmobar ~/.xmonad/xmobar/xmobarrc"
442 -- the xmonad, ya know...what the wm is named after!
443 xmonad $ ewmh def
444 { manageHook = myManageHook <+> manageDocks
445 , handleEventHook = docksEventHook
446 , modMask = myModMask
447 , terminal = myTerminal
448 , startupHook = myStartupHook
449 , layoutHook = showWName' myShowWNameTheme $ myLayoutHook
450 , workspaces = myWorkspaces
451 , borderWidth = myBorderWidth
452 , normalBorderColor = myNormColor
453 , focusedBorderColor = myFocusColor
454 , logHook = dynamicLogWithPP
455 $ namedScratchpadFilterOutWorkspacePP
456 $ xmobarPP
457 { ppOutput = hPutStrLn xmproc
458 , ppCurrent = xmobarColor (myColor "green-bright") ""
459 . wrap "<fn=3>" "</fn>" -- toki pona
460 . wrap "[" "]"
461 -- . wrap " " " " -- normal
462 , ppVisible = xmobarColor (myColor "green-bright") "" . clickable
463 , ppHidden = xmobarColor (myColor "blue-bright") ""
464 . wrap "" "'"
465 . clickable
466 , ppHiddenNoWindows = xmobarColor (myColor "gray2") "" . clickable
467 --, ppHiddenNoWindows = myHiddenNoWindows
468 , ppTitle = xmobarColor (myColor "gray4") "" . shorten 60
469 , ppSep = xmobarColor (myColor "gray3") "" " | "
470 , ppWsSep = " "
471 , ppUrgent = xmobarColor (myColor "yellow") "" . wrap "!" "!"
472 , ppExtras = [myWindowCountLogger]
473 , ppOrder = \(ws:l:t:ex) -> [ws,l]++ex++[t]
474 }
475 } `additionalKeysP` myKeys
476