dotfiles/.config/xmonad/xmonad.hs

267 lines
9.9 KiB
Haskell

{-# OPTIONS_GHC -Wno-missing-signatures #-}
import Data.Map qualified as M
import Data.Monoid
import Graphics.X11.ExtraTypes.XF86
import System.Exit
import Text.Printf
import XMonad
import XMonad.Actions.CycleWS
import XMonad.Actions.Submap
import XMonad.Actions.ToggleFullFloat
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.InsertPosition
import XMonad.Hooks.ManageDocks (ToggleStruts (..), avoidStruts, manageDocks)
import XMonad.Hooks.Place
import XMonad.Hooks.StatusBar
import XMonad.Hooks.WindowSwallowing
import XMonad.Layout.Grid
import XMonad.Layout.Renamed (named)
import XMonad.StackSet qualified as W
import XMonad.Util.NamedScratchpad
myTerminal, myEditor :: String
myTerminal = "st"
myEditor = "nvim"
myWorkspaces :: [String]
myWorkspaces = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
myBorderWidth :: Dimension
myBorderWidth = 1
myNormalBorderColor, myFocusedBorderColor :: String
myNormalBorderColor = "#222222"
myFocusedBorderColor = "#80b7ff"
floatClasses, swallowClasses :: [String]
floatClasses = ["Arandr", "Nsxiv"]
swallowClasses = ["St", "XTerm"]
myKeys :: XConfig Layout -> M.Map (KeyMask, KeySym) (X ())
myKeys (XConfig {XMonad.modMask = modMask, XMonad.workspaces = workspaces}) =
M.fromList $
[ -- Common programs
((modMask, xK_Return), spawn myTerminal),
((modMask, xK_p), spawnDmenu "dmenu_run"),
((modMask, xK_w), spawn "firefox"),
((modMask .|. controlMask, xK_q), spawn "qutebrowser"),
((modMask, xK_e), spawnTerminal myEditor),
((modMask, xK_f), spawnTerminal "lf"),
((modMask, xK_t), spawnTerminal "ncmpcpp"),
((modMask .|. controlMask, xK_e), spawnTerminal "ncspot"),
((modMask, xK_v), spawnTerminal "pulsemixer"),
((modMask .|. controlMask, xK_y), spawn "pavucontrol"),
((modMask .|. controlMask, xK_semicolon), spawn "simplescreenrecorder"),
((modMask .|. controlMask, xK_apostrophe), spawn "obs"),
((modMask .|. controlMask, xK_o), spawnTerminal "cava"),
((modMask .|. controlMask, xK_l), spawn "run-i3lock"),
((modMask .|. controlMask, xK_d), spawn "arandr"),
((modMask .|. controlMask, xK_v), spawn "screenlayouts-open"),
((modMask .|. controlMask, xK_w), spawn "wallpapers-open"),
((modMask .|. controlMask, xK_bracketright), spawn "find ~/pictures/screenshots -type f | nsxiv -ti"),
-- Screenshotting
((0, xK_Print), spawn "epicshot -cs select"),
((controlMask, xK_Print), spawn "epicshot -cs full"),
((modMask, xK_Print), spawn "epicshot -so select"),
((modMask .|. controlMask, xK_r), spawn "epicshot -cs select"),
((modMask .|. controlMask, xK_t), spawn "epicshot -cs full"),
((modMask .|. controlMask, xK_g), spawn "epicshot -so select"),
-- Faux function row
((modMask .|. controlMask, xK_F5), spawn "mpc prev"),
((modMask .|. controlMask, xK_F6), spawn "mpc next"),
((modMask .|. controlMask, xK_F7), spawn "mpc toggle"),
((modMask .|. controlMask, xK_F8), spawn "mpc stop"),
((modMask .|. controlMask, xK_F9), spawn "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle && pipe_volume"),
((modMask .|. controlMask, xK_F10), spawn "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- && pipe_volume"),
((modMask .|. controlMask, xK_F11), spawn "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ && pipe_volume"),
((modMask .|. controlMask, xK_F12), spawn "run-i3lock"),
-- Special keys
((0, xF86XK_Explorer), spawnTerminal "nnn"),
((0, xF86XK_Search), spawnDmenu "dmenu_run"),
((0, xF86XK_Calculator), spawnTerminal "bc -i"),
((0, xF86XK_Tools), spawnTerminal "ncmpcpp"),
((0, xF86XK_AudioPrev), spawn "mpc prev"),
((0, xF86XK_AudioNext), spawn "mpc next"),
((0, xF86XK_AudioPlay), spawn "mpc toggle"),
((0, xF86XK_AudioStop), spawn "mpc stop"),
((0, xF86XK_AudioMute), spawn "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle && pipe_volume"),
((0, xF86XK_AudioLowerVolume), spawn "wpctl set-mute @DEFAULT_AUDIO_SINK@ 5%- && pipe_volume"),
((0, xF86XK_AudioRaiseVolume), spawn "wpctl set-mute @DEFAULT_AUDIO_SINK@ 5%+ && pipe_volume"),
-- Layout switching
( (modMask, xK_a),
submap . M.fromList $
[ ((modMask, xK_t), sendMessage $ JumpToLayout "Tall"),
((modMask, xK_y), sendMessage $ JumpToLayout "Wide"),
((modMask, xK_g), sendMessage $ JumpToLayout "Grid"),
((modMask, xK_f), sendMessage $ JumpToLayout "Full"),
((modMask, xK_a), sendMessage NextLayout)
]
),
((modMask, xK_b), sendMessage ToggleStruts),
-- Basic window management
((modMask, xK_j), windows W.focusDown),
((modMask, xK_k), windows W.focusUp),
((modMask .|. shiftMask, xK_j), windows W.swapDown),
((modMask .|. shiftMask, xK_k), windows W.swapUp),
-- Master control
((modMask, xK_h), sendMessage Shrink),
((modMask, xK_l), sendMessage Expand),
((modMask, xK_i), sendMessage $ IncMasterN 1),
((modMask, xK_d), sendMessage $ IncMasterN $ -1),
((modMask, xK_s), windows W.focusMaster),
((modMask .|. shiftMask, xK_s), windows W.swapMaster),
-- Window actions
((modMask .|. shiftMask, xK_c), kill),
((modMask .|. shiftMask, xK_f), withFocused toggleFullFloat),
((modMask .|. shiftMask, xK_space), withFocused toggleFloat),
-- Scratchpads
((modMask .|. controlMask, xK_Return), namedScratchpadAction myScratchPads "terminal"),
((modMask .|. controlMask, xK_c), namedScratchpadAction myScratchPads "ncmpcpp"),
-- Session
((modMask .|. controlMask, xK_Delete), io exitSuccess),
((modMask .|. controlMask, xK_s), spawn "xmonad --restart && notify-send 'xmonad' 'Successfully recompiled and restarted.'")
]
-- Workspace viewing and shifting
++ [ ((modMask .|. m, k), windows $ f i)
| (k, i) <- zip [xK_1 .. xK_9] workspaces,
(m, f) <- [(0, W.view), (shiftMask, W.shift)]
]
where
toggleFloat :: Window -> X ()
toggleFloat w = do
isFloating <- gets (M.member w . W.floating . windowset)
if isFloating
then windows $ W.sink w
else withFocused float
spawnTerminal :: String -> X ()
spawnTerminal x = do
spawn $ printf "%s -e %s" myTerminal x
spawnDmenu :: String -> X ()
spawnDmenu x = do
spawn $ printf "%s -h %s -fn %s -nb '%s' -nf '%s' -sb '%s' -sf '%s'" x "17" "Terminus-8" "#1d2021" "#ebdbb2" "#fabd2f" "#282828"
myMouseBindings :: XConfig Layout -> M.Map (KeyMask, Button) (Window -> X ())
myMouseBindings (XConfig {XMonad.modMask = modMask}) =
M.fromList
[ -- Float and move window
((modMask, button1), \w -> focus w >> mouseMoveWindow w),
-- Shift window to master
((modMask, button2), \w -> focus w >> windows W.shiftMaster),
-- Float and resize window
((modMask, button3), \w -> focus w >> mouseResizeWindow w),
-- Go to previous workspace
((modMask, button4), const prevWS),
-- Go to next workspace
((modMask, button5), const nextWS),
-- Shift window to previous workspace
((modMask .|. shiftMask, button4), \_ -> shiftToPrev >> prevWS),
-- Shift window to next workspace
((modMask .|. shiftMask, button5), \_ -> shiftToNext >> nextWS)
]
myLayoutHook =
avoidStruts $
tall ||| wide ||| grid ||| full
where
tall =
named "Tall" $
Tall 1 (3 / 100) (1 / 2)
wide =
named "Wide" $
Mirror tall
grid =
named
"Grid"
Grid
full =
named
"Full"
Full
-- SCRATCHPADS ---------------------------------------------------------
myScratchPads :: [NamedScratchpad]
myScratchPads =
[ constructScratchpad "terminal" "scTerminal" Nothing,
constructScratchpad "ncmpcpp" "scNcmpcpp" (Just "ncmpcpp")
]
where
constructScratchpad :: String -> String -> Maybe String -> NamedScratchpad
constructScratchpad name cls maybeExec =
NS
name
( case maybeExec of
Just exec -> printf "%s -c %s -e %s" myTerminal cls exec
Nothing -> printf "%s -c %s" myTerminal cls
)
(className =? cls)
(customFloating $ W.RationalRect (3 / 5) (4 / 6) (1 / 5) (1 / 6))
-- HOOKS ---------------------------------------------------------------
myManageHook :: ManageHook
myManageHook =
composeAll
[ placeHook simpleSmart,
manageDocks,
namedScratchpadManageHook myScratchPads,
insertPosition End Newer,
composeAll [className =? c --> doFloat | c <- floatClasses]
]
myEventHook :: Event -> X All
myEventHook =
swallowEventHook (foldr1 (<||>) $ map (className =?) swallowClasses) (return True)
myStartupHook :: X ()
myStartupHook = do
spawn "initialize_pipes"
-- XMOBAR --------------------------------------------------------------
myPP :: PP
myPP =
def
{ ppSep = sep " | ",
ppCurrent = current . wrap "" "*",
ppHidden = noScratchPad,
ppHiddenNoWindows = const ""
}
where
noScratchPad :: String -> String
noScratchPad ws = if ws == "NSP" then "" else ws
sep, current :: String -> String
sep = xmobarColor "#777777" ""
current = xmobarColor "#6eadff" ""
-- MAIN ----------------------------------------------------------------
main :: IO ()
main =
xmonad
. withSB (statusBarProp "xmobar-top" $ pure myPP)
. withSB (statusBarProp "xmobar-bottom" $ pure myPP)
. toggleFullFloatEwmhFullscreen
. ewmhFullscreen
. ewmh
$ def
{ borderWidth = myBorderWidth,
normalBorderColor = myNormalBorderColor,
focusedBorderColor = myFocusedBorderColor,
layoutHook = myLayoutHook,
workspaces = myWorkspaces,
manageHook = myManageHook,
handleEventHook = myEventHook,
startupHook = myStartupHook,
mouseBindings = myMouseBindings,
keys = myKeys,
focusFollowsMouse = True,
clickJustFocuses = False,
modMask = mod4Mask
}