import XMonad import XMonad.Actions.CycleWS qualified as WS import XMonad.Actions.Navigation2D (navigation2DP, windowGo, windowSwap) import XMonad.Hooks.EwmhDesktops import XMonad.Hooks.ManageDocks qualified as Docks import XMonad.Hooks.ManageHelpers (doCenterFloat, doFullFloat, isDialog, isFullscreen) import XMonad.Hooks.SetWMName import XMonad.Layout.BinarySpacePartition import XMonad.Layout.BorderResize (borderResize) import XMonad.Layout.NoBorders (smartBorders) import XMonad.Layout.ThreeColumns import XMonad.Layout.ToggleLayouts (ToggleLayout (..), toggleLayouts) import XMonad.ManageHook (doFloat) import XMonad.StackSet as W import XMonad.Util.EZConfig qualified as EZ import XMonad.Util.NamedScratchpad import XMonad.Util.Ungrab (unGrab) import XMonad.Util.WorkspaceCompare qualified as WS import Control.Monad (when) import Numeric.Natural import System.Environment (getArgs) import System.FilePath (()) import System.Info (arch, os) import System.Posix.Process (executeFile) import Text.Printf (printf) compiledConfig = printf "xmonad-%s-%s" arch os compileRestart resume = do dirs <- asks directories whenX (recompile dirs True) $ do when resume writeStateToFile catchIO ( do args <- getArgs executeFile (cacheDir dirs compiledConfig) False args Nothing ) myLayout = smartBorders . borderResize . Docks.avoidStruts $ toggleLayouts Full emptyBSP main :: IO () main = getDirectories >>= launch myConfig -- change size of window using direction so that it can be used together with the navigation2D function -- see: similar to windowGo and windowSwap windowMoveSplit :: Direction2D -> Bool -> X () windowMoveSplit direction _ = sendMessage $ MoveSplit direction data VolumeCommand = ToggleVolume | LowerVolume Natural | RaiseVolume Natural interpretVolumeCommand :: VolumeCommand -> String interpretVolumeCommand command = "amixer -q set Master " <> cmd where cmd = case command of ToggleVolume -> "toggle" LowerVolume delta -> show delta <> "%-" RaiseVolume delta -> show delta <> "%+" changeVolume :: VolumeCommand -> X () changeVolume = spawn . interpretVolumeCommand myWorkspaceFilter :: X WS.WorkspaceSort myWorkspaceFilter = do sortXineramaAware <- WS.getSortByXineramaRule pure $ sortXineramaAware . WS.filterOutWs [scratchpadWorkspaceTag] scratchpads = [ NS "notes" "emacsclient -c -F '((name . \"gtd\"))'" (resource =? "gtd") doCenterFloat , -- (customFloating $ W.RationalRect (1/6) (1/6) (2/3) (2/3)) NS "shell" "alacritty --class scratchpad" (resource =? "scratchpad") (customFloating $ W.RationalRect (1 / 6) (1 / 6) (2 / 3) (2 / 3)) ] myConfig = addEwmhWorkspaceSort myWorkspaceFilter . ewmhFullscreen . ewmh . Docks.docks . nav $ def { modMask = mod4Mask -- Use Super instead of Alt , terminal = "alacritty" , layoutHook = myLayout , handleEventHook = handleEventHook def <+> fullscreenEventHook , -- this seems to be necessary to make java gui applications work :( startupHook = ewmhDesktopsStartup >> setWMName "LG3D" , manageHook = mconcat [ namedScratchpadManageHook scratchpads , isDialog --> doFloat , isFullscreen --> doFullFloat , className =? "steam_proton" --> doFloat , manageHook def ] } `EZ.additionalKeysP` [ ("M-S-z", spawn "xscreensaver-command -lock") , ("M-S-r", compileRestart True) , ("M-S-q", restart "xmonad" True) , ("M-C-s", unGrab *> spawn "scrot -s") , ("M-S-s", sendMessage Docks.ToggleStruts) , ("M-f", sendMessage (Toggle "Full")) , ("M-p", spawn appLauncher) , ("M-i", spawn passLauncher) , ("M-w", kill) , ("M-l", WS.toggleWS) , ("M-g", WS.prevWS) , ("M-C-g", WS.swapPrevScreen) , ("M-S-g", WS.shiftPrevScreen) , ("M-r", WS.nextWS) , ("M-C-r", WS.swapNextScreen) , ("M-S-r", WS.shiftNextScreen) , -- scratchpads ("M-s M-t", namedScratchpadAction scratchpads "shell") , ("M-s M-s", namedScratchpadAction scratchpads "notes") , -- backlight control ("", spawn "xbacklight -dec 5") , ("", spawn "xbacklight -inc 5") , ("", spawn "xbacklight -dec 5") , ("", spawn "xbacklight -inc 5") , -- transparency ("S-", spawn "picom-trans -c -5") , ("S-", spawn "picom-trans -c +5") , ("M-S-d", spawn "picom-trans -c +5") , ("M-S-b", spawn "picom-trans -c -5") , -- volume control ("", changeVolume ToggleVolume) , ("", changeVolume $ LowerVolume 5) , ("", changeVolume $ RaiseVolume 5) , ("M-d", changeVolume $ RaiseVolume 5) , ("M-b", changeVolume $ LowerVolume 5) , ("M-a", sendMessage Balance) , ("M-S-a", sendMessage Equalize) , ("M-o", sendMessage Rotate) , ("M-y", withFocused $ windows . W.sink) ] where -- navigate using dvorak bindings nav = navigation2DP def ("c", "h", "t", "n") [("M-", windowGo), ("M-C-", windowSwap), ("M-S-", windowMoveSplit)] True appLauncher = "rofi -show combi -modes combi -combi-modes window,drun,run,ssh" passLauncher = "rofi-pass" -- myManageHook :: ManageHook -- myManageHook = composeAll -- [ className =? "Gimp" --> doFloat -- , isDialog --> doFloat -- ]