{-# LANGUAGE BlockArguments #-} -- Imports import XMonad import Data.Monoid import System.Exit import XMonad.Util.Run import XMonad.Util.SpawnOnce import XMonad.Hooks.DynamicLog import XMonad.Hooks.ManageDocks import XMonad.Layout.Spacing import XMonad.Layout.ThreeColumns import XMonad.Layout.LayoutModifier import XMonad.Layout.Renamed import XMonad.Hooks.SetWMName import XMonad.Util.Cursor import XMonad.Layout.NoBorders import XMonad.Layout.PerWorkspace import XMonad.Layout.LimitWindows import XMonad.Hooks.EwmhDesktops import XMonad.Util.EZConfig import XMonad.Util.NamedScratchpad import XMonad.Actions.TopicSpace import XMonad.Prompt import XMonad.Prompt.FuzzyMatch import XMonad.Prompt.Workspace import XMonad.Hooks.WorkspaceHistory (workspaceHistoryHook) import XMonad.Hooks.DynamicProperty import qualified XMonad.StackSet as W import qualified Data.Map as M import Text.Regex.Posix import XMonad.Util.WorkspaceCompare ( getSortByIndex, filterOutWs ) -- variables myTerminal = "alacritty" myBorderWidth = 1 myNormalBorderColor = "#dcdccc" myFocusedBorderColor = "#dca3a3" myModMask = mod4Mask -- scratchpads myScratchpads :: [NamedScratchpad] myScratchpads = [ NS "cmus" "st -n cmus -e cmus" (resource =? "cmus") (customFloating $ W.RationalRect (1/6) (1/6) (4/6) (4/6)) , NS "nnn" "st -t nnn -e nnnwrapper" (title =? "nnn") (customFloating $ W.RationalRect (1/4) (1/6) (2/4) (4/6)) , NS "neomutt" "st -t neomutt -e neomutt -f posteo-Inbox" (title =? "neomutt") (customFloating $ W.RationalRect (1/10) (1/10) (8/10) (8/10)) , NS "vimwiki" "st -t vimwiki -e vwwrapper" (title =? "vimwiki") (customFloating $ W.RationalRect (1/6) (1/6) (2/3) (2/3)) , NS "keepassxc" "keepassxc ~/dokumente/Database.kdbx" (title =? "Database.kdbx - KeePassXC" <||> title =? "Database.kdbx [Gesperrt] - KeePassXC") defaultFloating , NS "discord" "firejail discord" (title *!? "Discord") (customFloating $ W.RationalRect (1/10) (1/10) (8/10) (8/10)) ] -- Topic Space topicItems :: [TopicItem] topicItems = [ noAction "1" "~/" , noAction "2" "~/" , noAction "3" "~/" , noAction "4" "~/" , noAction "5" "~/" , TI "recipes" "~/recipes" (switchToLayout "Programming" *> spawnShellAndExecute "hugo server" *> proc (inProgram "librewolf") *> spawnEditor) , TI "alkaa" "~/alkaa" (switchToLayout "Programming" *> spawnShell *> spawnEditor) , TI "steam" "~" (switchToLayout "Steam" *> spawn "steam") , TI "game" "~" (switchToLayout "Full") , TI "micro" "~/projekte/microcontroller" (switchToLayout "Programming" *> spawnShell *> spawnEditor) , TI "aoc" "~/projekte/aoc" (switchToLayout "Programming" *> spawnShell *> spawnEditor) ] myTopicConfig :: TopicConfig myTopicConfig = def { topicDirs = tiDirs topicItems , topicActions = tiActions topicItems , defaultTopicAction = const (pure ()) -- by default, do nothing , defaultTopic = "1" -- fallback } spawnShell :: X () spawnShell = proc $ termInDir >-$ currentTopicDir myTopicConfig spawnEditor :: X () spawnEditor = proc $ (termInDir >-$ currentTopicDir myTopicConfig) >-> execute "nvim" switchToLayout :: String -> X () switchToLayout = sendMessage . JumpToLayout spawnShellAndExecute :: String -> X () spawnShellAndExecute cmd = proc $ (termInDir >-$ currentTopicDir myTopicConfig) >-> execute cmd toggleTopic :: X () toggleTopic = switchNthLastFocusedByScreen myTopicConfig 1 myWorkSpacePrompt :: XPConfig -> (String -> X ()) -> X () myWorkSpacePrompt c job = do ws <- gets (W.workspaces . windowset) sort <- getSortByIndex let filter = filterOutWs ["1", "2", "3", "4", "5", "NSP"] let ts = map W.tag $ filter ws mkXPrompt (Wor "") c (mkComplFunFromList' c ts) job topicPrompt :: XPConfig topicPrompt = def { historySize = 20 -- No history in the prompt. , fgColor = "#dcdccc" , fgHLight = "#3f3f3f" , bgHLight = "#dca3a3" , alwaysHighlight = True -- Current best match , font = "xft:Iosevka-11" , height = 25 , position = Top , promptBorderWidth = myBorderWidth -- Fit in with rest of config , borderColor = "#dca3a3" , maxComplRows = Just 5 -- Max rows to show in completion window , searchPredicate = fuzzyMatch , sorter = fuzzySort } -- keybindings myAdditionalKeys :: [(String, X ())] myAdditionalKeys = -- xmonad specific [ ("M-q", spawn "xmonad --recompile; xmonad --restart") , ("M-S-c", kill) , ("M-j", windows W.focusDown) , ("M-k", windows W.focusUp) , ("M-S-j", windows W.swapDown) , ("M-S-k", windows W.swapUp) , ("M-h", sendMessage Shrink) , ("M-l", sendMessage Expand) , ("M-,", sendMessage (IncMasterN 1)) , ("M-S-,", sendMessage (IncMasterN (-1))) , ("M-.", sendMessage ToggleStruts) -- dmenu prompts , ("M-", spawn "dm-recent-aliases") , ("M-p s", spawn "dm-screenshot") , ("M-p k", spawn "dm-kill") -- scratchpads , ("M-s c", namedScratchpadAction myScratchpads "cmus") , ("M-s m", namedScratchpadAction myScratchpads "neomutt") , ("M-s v", namedScratchpadAction myScratchpads "vimwiki") , ("M-s d", namedScratchpadAction myScratchpads "discord") , ("M-S-a", namedScratchpadAction myScratchpads "keepassxc") , ("M-n", namedScratchpadAction myScratchpads "nnn") -- some shortcuts for prorgrams , ("M-S-", spawnShell) , ("M-b", spawn "librewolf") -- layout , ("M-t t", switchToLayout "Tall") , ("M-t h", switchToLayout "Programming") , ("M-t f", switchToLayout "Full") , ("M-S-f", withFocused $ windows . W.sink) -- media keys , ("", spawn "amixer sset Master toggle") , ("", spawn "amixer sset Master 5%- unmute") , ("", spawn "amixer sset Master 5%+ unmute") , ("", spawn "amixer sset Capture toggle") , ("M-S-m", spawn "amixer sset Capture toggle") -- lock screen , ("M-S-l", spawn "slock") -- workspace switching , ("M-", toggleTopic) , ("M-", myWorkSpacePrompt topicPrompt (switchTopic myTopicConfig)) , ("M-S-", myWorkSpacePrompt topicPrompt (windows . W.shift)) ] ++ -- use 1-5 for switching (Shift Mod shifts into) workspaces 1-5 [ ("M-" ++ m ++ k, f i) | (i, k) <- zip (topicNames topicItems) (map show [1 .. 5 :: Int]) , (f, m) <- [(switchTopic myTopicConfig, ""), (windows . W.shift, "S-")] ] -- Layouts mySpacing :: Integer -> l a -> XMonad.Layout.LayoutModifier.ModifiedLayout Spacing l a mySpacing i = spacingRaw True (Border i i i i) True (Border i i i i) True myLayout = avoidStruts $ tiling ||| hacking ||| full ||| steam where tiling = renamed [Replace "Tall"] $ smartBorders $ mySpacing 6 $ Tall 1 (3/100) (1/2) hacking = renamed [Replace "Programming"] $ smartBorders $ mySpacing 6 $ Tall 1 (3/100) (5/8) full = noBorders Full steam = renamed [Replace "Steam"] $ noBorders $ mySpacing 3 $ limitWindows 2 $ ThreeCol 1 (3/100) (5/8) -- Regex lifted up to use in manageHook (*!?) :: Functor f => f String -> String -> f Bool q *!? x = fmap (=~ x) q -- window rules myManageHook = composeAll . concat $ [ [ resource =? "desktop_window" --> doIgnore ] , [ resource =? "kdesktop" --> doIgnore ] , [ ( className =? "LibreWolf" <&&> role =? "Organizer" ) --> doFloat ] -- Steam and games , [ className =? "Steam" --> doShift "steam" ] , [ ( className =? "Steam" <&&> title *!? "Friends List" <||> title *!? "News" ) --> doF W.swapDown ] , [ title =? t <&&> title *!? t --> doShift "game" | t <- myGames ] -- float specific classes , [ className =? c --> doFloat | c <- myFloatingClasses ] -- scratchpads , [ namedScratchpadManageHook myScratchpads ] ] where role = stringProperty "WM_WINDOW_ROLE" myFloatingClasses = ["Gimp", "Origin"] myGames = ["Grim Dawn", "Der Herr der Ringe Onlineā„¢", "Dota 2", "Project Zomboid", "Valheim", "Factorio", "Path of Exile", "Paradox Launcher", "Europa Universalis IV", "Bannerlord"] ------------------------------------------------------------------------ -- Event handling -- * EwmhDesktops users should change this to ewmhDesktopsEventHook -- -- Defines a custom handler function for X Events. The function should -- return (All True) if the default handler is to be run afterwards. To -- combine event hooks use mappend or mconcat from Data.Monoid. -- myEventHook = dynamicPropertyChange "WM_NAME" (title =? "Database.kdbx - KeePassXC" <||> title =? "Database.kdbx [Gesperrt] - KeePassXC" --> floating) where floating = customFloating $ W.RationalRect (1/8) (1/8) (3/4) (3/4) -- Startup hook myStartupHook = do setWMName "LG3D" setDefaultCursor xC_left_ptr spawnOnce("redshift -c /home/max/.config/redshift/redshiftrc") spawnOnce("feh --bg-fill ~/bilder/bg.jpg") spawnOnce("/usr/bin/syncthing -no-browser -logfile=default") -- Main main = do xmproc <- spawnPipe "xmobar /home/max/.config/xmobar/xmobarrc" xmonad $ spawnExternalProcess def $ docks $ def { -- simple stuff terminal = myTerminal, borderWidth = myBorderWidth, modMask = myModMask, workspaces = topicNames topicItems, normalBorderColor = myNormalBorderColor, focusedBorderColor = myFocusedBorderColor, -- hooks, layouts layoutHook = myLayout, manageHook = myManageHook, handleEventHook = myEventHook, logHook = workspaceHistoryHook >> (dynamicLogWithPP $ filterOutWsPP ["NSP"] $ xmobarPP { ppCurrent = xmobarColor "#dca3a3" "" . wrap "[ " " ]", ppHidden = xmobarColor "#8cd0d3" "", ppLayout = xmobarColor "#8c8cbc" "", ppTitle = xmobarColor "#ffcfaf" "" . shorten 100, ppSep = " | ", ppOutput = hPutStrLn xmproc }), startupHook = myStartupHook } `additionalKeysP` myAdditionalKeys