import XMonad import qualified XMonad.StackSet as W import XMonad.ManageHook -- data import Data.Tree import qualified Data.Map as M -- actions import XMonad.Actions.CopyWindow import XMonad.Actions.CycleWS import XMonad.Actions.GridSelect import XMonad.Actions.SwapWorkspaces import qualified XMonad.Actions.TreeSelect as TS -- layout modifiers import XMonad.Layout.Spacing import XMonad.Layout.WindowNavigation as WN import XMonad.Layout.Maximize import XMonad.Layout.Fullscreen import XMonad.Layout.NoBorders -- Layouts import XMonad.Layout.BinarySpacePartition as BSP import XMonad.Layout.Grid import XMonad.Layout.Tabbed -- hooks import XMonad.Hooks.SetWMName import XMonad.Hooks.ManageDocks import XMonad.Hooks.EwmhDesktops (ewmh) -- utilities import XMonad.Util.SpawnOnce import XMonad.Util.EZConfig import XMonad.Util.Cursor import XMonad.Util.NamedScratchpad -- defaults myModMask = mod4Mask altMask = mod1Mask myLockscreen = "notify-send 'to be set up!' 'to be set up!'" myColorPicker = "colorpicker --short --one-shot --preview | xsel -b" myFont = "xft:Hack:style=Regular:size=14" myExtraWorkspaces = [(xK_0, "十")] -- , (xK_comma, " 十一 "), (xK_period, " 十二 "), (xK_slash, " 十三 ")] myWorkspaces = ["一", "二", "三", "四", "五", "六", "七", "八", "九"] ++ (map snd myExtraWorkspaces) myScratchpads = [ NS "Term 0" "alacritty -t 'Term 0'" (title =? "Term 0") (customFloating $ W.RationalRect (1/16) (1/16) (7/8) (7/8)) , NS "Term 1" "alacritty -t 'Term 1'" (title =? "Term 1") (customFloating $ W.RationalRect (1/16) (1/16) (7/8) (7/8)) , NS "Term 2" "alacritty -t 'Term 2'" (title =? "Term 2") (customFloating $ W.RationalRect (1/16) (1/16) (7/8) (7/8)) , NS "OBS" "obs" (className =? "obs") (customFloating $ W.RationalRect (1/16) (1/16) (7/8) (7/8)) , NS "lf" "alacritty -t 'lf' -e 'lf'" (title =? "lf") (customFloating $ W.RationalRect (1/16) (1/16) (7/8) (7/8)) , NS "calc" "kcalc" (className =? "kcalc") defaultFloating , NS "arandr" "arandr" (className =? "Arandr") defaultFloating , NS "BPYTOP" "alacritty -t 'BPYTOP' -e 'bpytop'" (title =? "BPYTOP") (customFloating $ W.RationalRect (1/16) (1/16) (7/8) (7/8)) ] where role = stringProperty "WM_WINDOW_ROLE" myTabTheme = def { fontName = myFont , activeColor = "#755999" , inactiveColor = "#282c35" , activeBorderColor = "#755999" , inactiveBorderColor = "#313846" , activeTextColor = "#FFFFFF" , inactiveTextColor = "#d0d0d0" , decoHeight = 20 } myTSConfig = TS.TSConfig { TS.ts_hidechildren = False , TS.ts_background = 0xdd282c34 , TS.ts_font = myFont , TS.ts_node = (0xffd0d0d0, 0xff1c1f24) , TS.ts_nodealt = (0xffd0d0d0, 0xff282c34) , TS.ts_highlight = (0xffffffff, 0xff755999) , TS.ts_extra = 0xffd0d0d0 , TS.ts_node_width = 220 , TS.ts_node_height = 34 , TS.ts_originX = 10000 , TS.ts_originY = 100 , TS.ts_indent = 80 , TS.ts_navigate = TS.defaultNavigation } networkingTS = [ Node (TS.TSNode "KTorrent" "" (spawn "ktorrent")) [] , Node (TS.TSNode "TOR" "" (spawn "torbrowser-launcher")) [] , Node (TS.TSNode "Discord" "" (spawn "discord")) [] , Node (TS.TSNode "Icecat" "" (spawn "icecat")) [] , Node (TS.TSNode "Librewolf" "" (spawn "librewolf")) [] , Node (TS.TSNode "Brave" "" (spawn "brave")) [] , Node (TS.TSNode "Firefox" "" (spawn "firefox")) [] ] myNetworkingTS a = TS.treeselectAction a networkingTS powerTS = [ Node (TS.TSNode "Shutdown" "" (spawn "shutdown now")) [] , Node (TS.TSNode "Restart" "" (spawn "reboot")) [] ] myPowerTS a = TS.treeselectAction a powerTS mediaTS = [ Node (TS.TSNode "VLC" "" (spawn "vlc")) [] , Node (TS.TSNode "GIMP" "" (spawn "gimp")) [] , Node (TS.TSNode "Kdenlive" "" (spawn "kdenlive")) [] , Node (TS.TSNode "OBS" "" (spawn "OBS")) [] ] myMediaTS a = TS.treeselectAction a mediaTS gamingTS = [ Node (TS.TSNode "Minecraft" "" (spawn "minecraft-launcher")) [] , Node (TS.TSNode "osu!lazer" "" (spawn "env LUTRIS_SKIP_INIT=1 lutris lutris:rungameid/3")) [] , Node (TS.TSNode "Steam" "" (spawn "steam")) [] , Node (TS.TSNode "Lutris" "" (spawn "lutris")) [] ] myGamingTS a = TS.treeselectAction a gamingTS scratchpadTS = [ Node (TS.TSNode "Term 0" "" (namedScratchpadAction myScratchpads "Term 0")) [] , Node (TS.TSNode "Term 1" "" (namedScratchpadAction myScratchpads "Term 1")) [] , Node (TS.TSNode "Term 2" "" (namedScratchpadAction myScratchpads "Term 2")) [] , Node (TS.TSNode "OBS" "" (namedScratchpadAction myScratchpads "OBS")) [] , Node (TS.TSNode "lf" "" (namedScratchpadAction myScratchpads "lf")) [] , Node (TS.TSNode "BPYTOP" "" (namedScratchpadAction myScratchpads "BPYTOP")) [] , Node (TS.TSNode "Calculator" "" (namedScratchpadAction myScratchpads "calc")) [] , Node (TS.TSNode "Arandr" "" (namedScratchpadAction myScratchpads "arandr")) [] ] myScratchpadTS a = TS.treeselectAction a scratchpadTS xmonadTS = [ Node (TS.TSNode "Go To Window" "" (goToSelected defaultGSConfig)) [] , Node (TS.TSNode "Bring Window" "" (bringSelected defaultGSConfig)) [] , Node (TS.TSNode "Rotate Windows" "" (sendMessage Rotate)) [] , Node (TS.TSNode "Swap Windows" "" (sendMessage BSP.Swap)) [] , Node (TS.TSNode "Un/Maximize" "" (withFocused (sendMessage . maximizeRestore))) [] , Node (TS.TSNode "Sink Window" "" (withFocused $ windows . W.sink)) [] , Node (TS.TSNode "Sticky Window" "" (windows copyToAll)) [] , Node (TS.TSNode "Un-sticky Window" "" (killAllOtherCopies)) [] ] myXmonadTS a = TS.treeselectAction a xmonadTS devTS = [ Node (TS.TSNode "Android Studio" "" (spawn "android-studio")) [] , Node (TS.TSNode "VSCodium" "" (spawn "code")) [] ] myDevTS a = TS.treeselectAction a (devTS ++ vmTS) vmTS = [ Node (TS.TSNode "Virt Manager" "" (spawn "virt-manager")) [] , Node (TS.TSNode "VirtualBox" "" (spawn "virtualbox")) [] ] myVmTS a = TS.treeselectAction a vmTS utilTS = [ Node (TS.TSNode "Pavucontrol" "" (spawn "pavucontrol")) [] , Node (TS.TSNode "OBS" "" (spawn "obs")) [] , Node (TS.TSNode "Arandr" "" (spawn "arandr")) [] , Node (TS.TSNode "System Monitor" "" (spawn "alacritty -e bpytop")) [] , Node (TS.TSNode "File Manager" "" (spawn "dolphin")) [] , Node (TS.TSNode "Calculator" "" (spawn "kcalc")) [] ] myUtilTS a = TS.treeselectAction a utilTS myTreeMenu a = TS.treeselectAction a ([Node (TS.TSNode "Utilities" "" (return())) utilTS , Node (TS.TSNode "Networking" "" (return())) networkingTS , Node (TS.TSNode "Development" "" (return())) devTS , Node (TS.TSNode "Virtual Machines" "" (return())) vmTS , Node (TS.TSNode "XMonad" "" (return())) [ Node (TS.TSNode "Window/Layout" "" (return())) xmonadTS , Node (TS.TSNode "Scratchpads" "" (return())) scratchpadTS ] , Node (TS.TSNode "Gaming" "" (return())) gamingTS , Node (TS.TSNode "Media" "" (return())) mediaTS , Node (TS.TSNode "Power" "" (return())) powerTS , Node (TS.TSNode "Screenshot" "" (spawn "spectacle")) [] ]) sGap = 4 -- screen gap wGap = 10 -- window gap myGap = spacingRaw True (Border sGap sGap sGap sGap) True (Border wGap wGap wGap wGap) True myGap' = spacingRaw False (Border sGap sGap sGap sGap) True (Border wGap wGap wGap wGap) True main :: IO () main = do xmonad $ ewmh $ docks $ fullscreenSupport def { focusFollowsMouse = True , borderWidth = 2 , modMask = myModMask , workspaces = myWorkspaces , normalBorderColor = "#130F23" , focusedBorderColor = "#BF00FF" , layoutHook = avoidStruts $ maximize $ windowNavigation $ smartBorders $ myGap $ ( emptyBSP ||| tabbed shrinkText myTabTheme ||| emptyBSP ||| Grid) , manageHook = namedScratchpadManageHook myScratchpads <+> manageDocks <+> composeAll [ className =? "plasmashell" --> doIgnore , className =? "ksmserver" --> doIgnore , className =? "kcalc" --> doFloat , className =? "systemsettings" --> doFloat , className =? "confirm" --> doFloat , className =? "file_progress" --> doFloat , className =? "dialog" --> doFloat , className =? "download" --> doFloat , className =? "error" --> doFloat , className =? "notification" --> doFloat , className =? "splash" --> doFloat , className =? "toolbar" --> doFloat ] } `additionalMouseBindings` [ ((myModMask, 4), \w -> prevWS), ((myModMask, 5), \w -> nextWS) ] `additionalKeys` ([ ((myModMask, xK_Return), spawn ("open_terminal")) , ((myModMask .|. shiftMask, xK_q), kill1) -- modify gaps on runtime , ((myModMask, xK_equal), incWindowSpacing 1) , ((myModMask, xK_minus), decWindowSpacing 1) , ((myModMask .|. shiftMask, xK_equal), incScreenSpacing 1) , ((myModMask .|. shiftMask, xK_minus), decScreenSpacing 1) -- view prev/next workspaces , ((altMask, xK_h), prevWS) , ((altMask, xK_l), nextWS) -- do the same without the evil alt key , ((myModMask, xK_comma), prevWS) , ((myModMask, xK_period), nextWS) -- move to prev/next workspaces , ((altMask .|. shiftMask, xK_h), shiftToPrev >> prevWS) , ((altMask .|. shiftMask, xK_l), shiftToNext >> nextWS) -- do the same without the evil alt key (might remove either pair later) , ((myModMask .|. shiftMask, xK_comma), shiftToPrev >> prevWS) , ((myModMask .|. shiftMask, xK_period), shiftToNext >> nextWS) -- focus previous.next monitor , ((myModMask, xK_bracketleft), prevScreen) , ((myModMask, xK_bracketright), nextScreen) -- move window to previous/next monitor , ((myModMask .|. shiftMask, xK_bracketleft), shiftPrevScreen >> prevScreen) , ((myModMask .|. shiftMask, xK_bracketright), shiftNextScreen >> nextScreen) -- swap different screens , ((myModMask .|. controlMask, xK_bracketleft), swapPrevScreen) , ((myModMask .|. controlMask, xK_bracketright), swapNextScreen) , ((myModMask, xK_backslash), sendMessage ToggleStruts) -- toggle both bars , ((myModMask, xK_f), withFocused (sendMessage . maximizeRestore)) -- toggle maximize , ((myModMask .|. shiftMask, xK_f), withFocused $ windows . W.sink) -- unfloat windows -- cycle through windows , ((altMask, xK_j), windows W.focusDown) , ((altMask, xK_k), windows W.focusUp) -- 2D navigation , ((myModMask, xK_l), sendMessage $ Go R) , ((myModMask, xK_h), sendMessage $ Go L) , ((myModMask, xK_k), sendMessage $ Go U) , ((myModMask, xK_j), sendMessage $ Go D) -- swap windows , ((myModMask .|. shiftMask, xK_l), sendMessage $ WN.Swap R) , ((myModMask .|. shiftMask, xK_h), sendMessage $ WN.Swap L) , ((myModMask .|. shiftMask, xK_k), sendMessage $ WN.Swap U) , ((myModMask .|. shiftMask, xK_j), sendMessage $ WN.Swap D) -- resize , ((myModMask .|. mod1Mask, xK_l ), sendMessage $ ExpandTowards R) , ((myModMask .|. mod1Mask, xK_h ), sendMessage $ ExpandTowards L) , ((myModMask .|. mod1Mask, xK_j ), sendMessage $ ExpandTowards D) , ((myModMask .|. mod1Mask, xK_k ), sendMessage $ ExpandTowards U) , ((myModMask .|. mod1Mask .|. shiftMask , xK_l ), sendMessage $ ShrinkFrom R) , ((myModMask .|. mod1Mask .|. shiftMask , xK_h ), sendMessage $ ShrinkFrom L) , ((myModMask .|. mod1Mask .|. shiftMask , xK_j ), sendMessage $ ShrinkFrom D) , ((myModMask .|. mod1Mask .|. shiftMask , xK_k ), sendMessage $ ShrinkFrom U) ] ++ [ -- for extra workspace(s) ((myModMask, key), (windows $ W.greedyView ws)) | (key,ws) <- myExtraWorkspaces ] ++ [ -- also for extra workspaces ((myModMask .|. shiftMask, key), (windows $ W.shift ws)) | (key,ws) <- myExtraWorkspaces ] ++ [ -- to swap workspace ((mod1Mask .|. shiftMask, k), windows $ swapWithCurrent i) | (i, k) <- zip myWorkspaces [xK_1, xK_2, xK_3, xK_4, xK_5, xK_6, xK_7, xK_8, xK_9, xK_0] ] ++ [ -- copy ((m .|. myModMask, k), windows $ f i) | (i, k) <- zip (myWorkspaces) [xK_1, xK_2, xK_3, xK_4, xK_5, xK_6, xK_7, xK_8, xK_9, xK_0] , (f, m) <- [(copy, shiftMask .|. altMask)] ] ++ [ -- for not swapping tags while using multihead ((m .|. myModMask, k), windows $ f i) | (i, k) <- zip myWorkspaces [xK_1, xK_2, xK_3, xK_4, xK_5, xK_6, xK_7, xK_8, xK_9, xK_0] , (f, m) <- [(W.view, 0), (W.shift, shiftMask)] ] -- ++ [ -- focus different monitors -- ((m .|. myModMask, key), screenWorkspace sc >>= flip whenJust (windows . f)) -- | (key, sc) <- zip [xK_bracketleft, xK_bracketright] [1,0] -- was [0..] *** change to match your screen order *** -- , (f, m) <- [(W.view, 0), (W.shift, shiftMask)] -- ] ) `additionalKeysP` [ ("M-c", spawn myColorPicker) -- Launchers , ("M-u", myDevTS myTSConfig) , ("M-x", myXmonadTS myTSConfig) , ("M-e", myMediaTS myTSConfig) , ("M-S-e", myGamingTS myTSConfig) , ("M-w", myScratchpadTS myTSConfig) , ("M-o", myUtilTS myTSConfig) , ("M-i", myNetworkingTS myTSConfig) , ("M-S-", myPowerTS myTSConfig) , ("M-p", myTreeMenu myTSConfig) , ("M-S-p", spawn "dmenu_run") ]