314 lines
9.6 KiB
Haskell
314 lines
9.6 KiB
Haskell
-- {{{ Imports
|
|
|
|
import Control.Monad (liftM2)
|
|
import Data.Map qualified as M
|
|
import XMonad
|
|
import XMonad.Actions.CopyWindow (copyToAll, killAllOtherCopies)
|
|
import XMonad.Actions.FloatSnap
|
|
import XMonad.Actions.Submap
|
|
import XMonad.Hooks.EwmhDesktops
|
|
import XMonad.Hooks.ManageDocks
|
|
import XMonad.Hooks.ManageHelpers
|
|
import XMonad.Hooks.OnPropertyChange (onXPropertyChange)
|
|
import XMonad.Hooks.StatusBar
|
|
import XMonad.Hooks.StatusBar.PP
|
|
import XMonad.Hooks.WindowSwallowing (swallowEventHook)
|
|
import XMonad.Layout.CenteredIfSingle
|
|
import XMonad.Layout.IndependentScreens
|
|
import XMonad.Layout.LayoutHints (hintsEventHook, layoutHints)
|
|
import XMonad.Layout.PerScreen
|
|
import XMonad.Layout.PerWorkspace
|
|
import XMonad.Layout.Renamed
|
|
import XMonad.Layout.Spacing
|
|
import XMonad.Layout.Tabbed
|
|
import XMonad.Layout.ThreeColumns
|
|
import XMonad.StackSet qualified as W
|
|
import XMonad.Util.EZConfig
|
|
import XMonad.Util.Hacks qualified as Hacks
|
|
import XMonad.Util.Loggers
|
|
import XMonad.Util.Paste
|
|
|
|
-- }}}
|
|
|
|
-- Statusbar {{{
|
|
|
|
pp' :: ScreenId -> PP -> PP
|
|
pp' s pp = (marshallPP s pp) { ppSort = ppSort pp }
|
|
|
|
pp :: PP
|
|
pp =
|
|
def
|
|
{ ppSep = tertiaryColor " ",
|
|
ppCurrent = brackitify,
|
|
ppHidden = secondaryColor,
|
|
ppHiddenNoWindows = tertiaryColor,
|
|
ppUrgent = red . wrap (yellow "!") (yellow "!"),
|
|
ppLayout = id,
|
|
ppTitle = shorten 80,
|
|
ppTitleSanitize = xmobarStrip,
|
|
ppOrder = \[workspaces, layout, windows, _] -> [workspaces, layout, windows],
|
|
ppExtras = [logTitles formatFocused formatUnfocused]
|
|
}
|
|
where
|
|
brackitify = wrap "〈" "〉"
|
|
formatFocused = secondaryColor . ppWindow
|
|
formatUnfocused = tertiaryColor . ppWindow
|
|
|
|
ppWindow = xmobarRaw . (\w -> if null w then "Untitled" else w) . shorten 16
|
|
|
|
primaryColor = xmobarColor "#000000" ""
|
|
secondaryColor = xmobarColor "#333333" ""
|
|
tertiaryColor = xmobarColor "#555555" ""
|
|
yellow = xmobarColor "#ff0" ""
|
|
red = xmobarColor "#ff5555" ""
|
|
|
|
-- }}}
|
|
|
|
-- Workspaces & screens {{{
|
|
|
|
-- Shift to workspace and view workspace
|
|
shiftAndView = doF . liftM2 (.) W.greedyView W.shift
|
|
|
|
-- }}}
|
|
|
|
-- Hooks {{{
|
|
|
|
-- startupHook {{{
|
|
myStartupHook =
|
|
do
|
|
spawn "killall polybar && polybar -r"
|
|
-- }}}
|
|
|
|
-- manageHook {{{
|
|
myManageHook :: ManageHook
|
|
myManageHook =
|
|
composeAll
|
|
[ isDialog --> doCenterFloat,
|
|
className =? "Zathura" --> doShift "1_info",
|
|
className =? "firefox" --> shiftAndView "1_www",
|
|
className =? "firefoxdeveloperedition" --> shiftAndView "1_www",
|
|
className =? "Anki" --> shiftAndView "1_etc",
|
|
className =? "Obsidian" --> shiftAndView "1_etc",
|
|
className =? "Launcher" --> doRectFloat (W.RationalRect 0.05 0.4 0.9 0.5),
|
|
className =? "Zettelkasten" --> doRectFloat (W.RationalRect 0.05 0.4 0.9 0.5),
|
|
className =? "Calculator" --> doCenterFloat,
|
|
className =? "feh" --> doCenterFloat,
|
|
-- Center matplotlib and prevent focus stealing
|
|
-- className =? "matplotlib" --> doRectFloat (W.RationalRect 0.5 0.5 0.5 0.5),
|
|
className =? "matplotlib" --> doCenterFloat,
|
|
className =? "Matplotlib" --> doCenterFloat,
|
|
className =? "Xournalpp" --> doRectFloat (W.RationalRect 0.5 0.5 0.5 0.5),
|
|
className =? "KeePassXC" --> doRectFloat (W.RationalRect 0.1 0.1 0.8 0.8),
|
|
className =? "flameshot" --> doRectFloat (W.RationalRect 0.1 0.1 0.8 0.8)
|
|
]
|
|
-- }}}
|
|
|
|
-- dynamicManageHook {{{
|
|
myDynamicManageHook :: ManageHook
|
|
myDynamicManageHook =
|
|
composeAll
|
|
[
|
|
title =? "Zettelkasten — Firefox Developer Edition" --> doShift "1_sh"
|
|
]
|
|
-- }}}
|
|
|
|
-- layoutHook {{{
|
|
myLayoutHook =
|
|
avoidStruts $
|
|
smartSpacingWithEdge 4 $
|
|
layoutHints $
|
|
onWorkspace "1_sh" (Tall nmaster delta 0.8) $
|
|
ifWider smallWidth (tWide ||| c3mWide ||| f) t
|
|
where
|
|
smallWidth = 1920
|
|
|
|
-- Tall layouts
|
|
tWide =
|
|
centeredIfSingle 0.62 1 t
|
|
t =
|
|
named "[]+" $
|
|
Tall nmaster delta ratio
|
|
|
|
-- Column layouts
|
|
c3mWide =
|
|
centeredIfSingle 0.62 1 c3m
|
|
c3m =
|
|
named "[|]" $
|
|
ThreeColMid nmaster delta ratio
|
|
|
|
-- Fullscreen layouts
|
|
f = named "[+]" Full
|
|
|
|
-- Modifiers
|
|
named n = renamed [Replace n]
|
|
nmaster = 1
|
|
ratio = 0.62
|
|
delta = 4 / 100
|
|
-- }}}
|
|
|
|
-- handleEventHook {{{
|
|
myHandleEventHook =
|
|
handleEventHook def
|
|
-- See window swallowing (https://hackage.haskell.org/package/xmonad-contrib-0.18.0/docs/XMonad-Hooks-WindowSwallowing.html)
|
|
<> swallowEventHook (className =? "Alacritty") (return True)
|
|
<> onXPropertyChange "WM_NAME" myDynamicManageHook
|
|
<> Hacks.windowedFullscreenFixEventHook
|
|
<> hintsEventHook
|
|
-- }}}
|
|
|
|
-- }}}
|
|
|
|
-- Main config {{{
|
|
|
|
myWorkspaces = [ "sh", "www", "dev", "info", "etc" ]
|
|
myWorkspaceKeys = [ "a", "s", "d", "f", "g" ]
|
|
mySharedWorkspaces = [ "shared" ]
|
|
mySharedWorkspaceKeys = [ "1" ]
|
|
-- Use Win key instead of Alt
|
|
myModMask = mod4Mask
|
|
|
|
myConfig =
|
|
def
|
|
{ terminal = "alacritty",
|
|
modMask = myModMask,
|
|
workspaces = withScreen 1 myWorkspaces ++ withScreen 2 mySharedWorkspaces,
|
|
-- Styling
|
|
focusedBorderColor = "#000",
|
|
normalBorderColor = "#0000",
|
|
borderWidth = 4,
|
|
-- Hooks
|
|
startupHook = myStartupHook,
|
|
manageHook = myManageHook <+> manageHook def,
|
|
layoutHook = myLayoutHook,
|
|
handleEventHook = myHandleEventHook
|
|
}
|
|
`removeKeysP` myRemoveKeys
|
|
`additionalKeysP` myKeys
|
|
`additionalMouseBindings` myMouseBindings
|
|
|
|
-- }}}
|
|
|
|
-- Keybindings {{{
|
|
|
|
-- Keybindings to be added/overridden
|
|
myKeys :: [(String, X ())]
|
|
myKeys =
|
|
[ ("M-<Space> s", unfloatFocusedW),
|
|
("M-<Space> <Space>", nextLayout), -- Cycle through layouts
|
|
("M-<Space> S-<Space>", defaultLayout), --
|
|
("M-<Space> M-<Space>", nextLayout), -- ..fat finger
|
|
("M-<Space> M-S-<Space>", defaultLayout), --
|
|
("<F8>", spawnKeepassXC),
|
|
("M-z", spawnZettelkasten),
|
|
("M-p", spawnLauncher),
|
|
("M-w", spawnWindowSwitcher),
|
|
("M-S-w", spawnWifiMenu),
|
|
("<Insert>", pasteSelection),
|
|
("<Print>", printScreen),
|
|
("<XF86AudioRaiseVolume>", raiseVol), -- Audio volume & playback
|
|
("<XF86AudioLowerVolume>", lowerVol), --
|
|
("<XF86AudioMute>", mute), --
|
|
("M-<Right>", nextTrack), --
|
|
("M-<Left>", prevTrack), --
|
|
("M-<Up>", play), --
|
|
("M-<Down>", pause), --
|
|
("<XF86MonBrightnessUp>", brighten), -- Brightness & hue controls
|
|
("<XF86MonBrightnessDown>", dim), --
|
|
("S-<XF86MonBrightnessUp>", warm), --
|
|
("S-<XF86MonBrightnessDown>", cool), --
|
|
("M-S-<XF86MonBrightnessUp>", resetTemp), --
|
|
("M-S-<XF86MonBrightnessDown>", resetTemp), --
|
|
("M-S-b", fullscreenBrowser),
|
|
("<XF86Calculator>", spawnCalculator),
|
|
("<XF86PowerOff>", spawn "systemctl suspend"), --TODO: Only enable this on laptop
|
|
("M-c", windows copyToAll),
|
|
("M-S-c", killAllOtherCopies),
|
|
("M-S-<Delete>", kill)
|
|
] ++
|
|
[ (m ++ k, windows $ f w) |
|
|
(m, f) <- zip ["M-", "M-S-"]
|
|
[W.greedyView, W.shift],
|
|
(k, w) <- zip myWorkspaceKeys
|
|
(withScreen 1 myWorkspaces)
|
|
++ zip mySharedWorkspaceKeys
|
|
(withScreen 2 mySharedWorkspaces)
|
|
]
|
|
|
|
zipKeyPrefixes :: [String] -> [String] -> [String]
|
|
zipKeyPrefixes prefixes keys = [prefix ++ key | prefix <- prefixes, key <- keys]
|
|
|
|
-- Keybindings to be removed
|
|
myRemoveKeys :: [String]
|
|
myRemoveKeys = "M-S-q" : zipKeyPrefixes ["M-", "M-S-"] (map show [ 1..5 ])
|
|
|
|
myMouseBindings =
|
|
[
|
|
((mod4Mask, button1), (\w -> focus w >> mouseMoveWindow w >> afterDrag (snapMagicMove (Just 50) (Just 50) w)))
|
|
, ((mod4Mask .|. shiftMask, button1), (\w -> focus w >> mouseMoveWindow w >> afterDrag (snapMagicResize [L,R,U,D] (Just 50) (Just 50) w)))
|
|
, ((mod4Mask, button3), (\w -> focus w >> mouseResizeWindow w >> afterDrag (snapMagicResize [R,D] (Just 50) (Just 50) w)))
|
|
]
|
|
|
|
unfloatFocusedW :: X ()
|
|
unfloatFocusedW = withFocused $ windows . W.sink
|
|
|
|
myStartupHook :: X ()
|
|
nextLayout = sendMessage NextLayout
|
|
|
|
defaultLayout :: X ()
|
|
defaultLayout = setLayout $ Layout myLayoutHook
|
|
|
|
spawnZettelkasten :: X ()
|
|
spawnZettelkasten = spawn "alacritty --class Zettelkasten,Zettelkasten -e nvim $(cat ~/.zk/current-zettel.txt)"
|
|
|
|
spawnKeepassXC :: X ()
|
|
spawnKeepassXC = spawn "keepassxc"
|
|
|
|
fullscreenBrowser :: X ()
|
|
fullscreenBrowser = spawn "firefox --fullscreen"
|
|
|
|
spawnWindowSwitcher = spawn "rofi -show window -show-icons"
|
|
spawnWifiMenu = spawn "rofi -show wifi -modi \"wifi:iwdrofimenu\""
|
|
|
|
spawnLauncher, spawnClipManager, spawnCalculator :: X ()
|
|
spawnLauncher = spawn "rofi -show drun -show-icons"
|
|
spawnClipManager = spawn "rofi -modi 'clipboard:greenclip print' -show clipboard -run-command '{cmd}'"
|
|
spawnCalculator = spawn "alacritty --class 'Calculator' -e ipython -i /home/h/.bin/calc.py"
|
|
|
|
printScreen :: X ()
|
|
printScreen = spawn "flameshot gui"
|
|
|
|
raiseVol, lowerVol, mute :: X ()
|
|
raiseVol = spawn "pactl set-sink-volume @DEFAULT_SINK@ +5%"
|
|
lowerVol = spawn "pactl set-sink-volume @DEFAULT_SINK@ -5%"
|
|
mute = spawn "pactl set-sink-mute @DEFAULT_SINK@ toggle"
|
|
|
|
nextTrack, prevTrack, play, pause :: X ()
|
|
nextTrack = spawn "playerctl next"
|
|
prevTrack = spawn "playerctl previous"
|
|
play = spawn "playerctl play"
|
|
pause = spawn "playerctl pause"
|
|
|
|
brighten, dim, warm, cool, resetTemp :: X ()
|
|
brighten = spawn "brightnessctl set 20+"
|
|
dim = spawn "brightnessctl set 20-"
|
|
warm = spawn "screen-temperature +50"
|
|
cool = spawn "screen-temperature -50"
|
|
resetTemp = spawn "screen-temperature 3000"
|
|
|
|
-- }}}
|
|
|
|
-- Main {{{
|
|
|
|
main :: IO ()
|
|
main =
|
|
do { xmonad } $
|
|
ewmh $
|
|
withEasySB
|
|
(sb1 <> sb2)
|
|
defToggleStrutsKey
|
|
myConfig
|
|
where
|
|
[sb1, sb2] = [statusBarProp "polybar" $ pure (pp' (S i) pp) | i <- [0 .. 1]]
|
|
|
|
-- }}}
|