import XMonad import XMonad.Util.EZConfig import XMonad.Layout.ThreeColumns import XMonad.Layout.WindowNavigation import XMonad.Layout.MultiToggle.Instances import XMonad.Layout.MultiToggle import XMonad.Layout.NoBorders import XMonad.Layout.IndependentScreens import XMonad.Actions.CopyWindow import XMonad.Actions.CycleWS import XMonad.Actions.EasyMotion (selectWindow) import XMonad.Hooks.EwmhDesktops import XMonad.Hooks.DynamicLog import XMonad.Hooks.StatusBar import XMonad.Hooks.StatusBar.PP import qualified XMonad.Layout.Magnifier as Mag import qualified Data.Map as M import qualified XMonad.StackSet as W import System.Exit import XMonad.Util.Loggers -- TODO: xmobar myWorkspaceNames = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] myScreens = 2 conf = def { layoutHook = myLayout , workspaces = withScreens myScreens myWorkspaceNames , modMask = mod4Mask } `additionalKeysP` myKeys -- main :: IO () main = xmonad $ ewmh $ withEasySB (statusBarProp "xmobar" (pure myXmobarPP)) defToggleStrutsKey conf -- Define the status bars for each screen -- myStatusBars :: [StatusBarConfig] -- myStatusBars = [ statusBarProp ("xmobar -x " ++ show sc) (pure myXmobarPP) | sc <- [0..myScreens - 1] ] -- main :: IO () -- main = xmonad . ewmh $ dynamicSBs myStatusBars conf myXmobarPP :: PP myXmobarPP = def { ppSep = magenta " • " , ppTitleSanitize = xmobarStrip , ppCurrent = xmobarBorder "Top" borderColor 2 . xmobarBorder "Bottom" borderColor 2 , ppUrgent = red . wrap (yellow "!") (yellow "!") , ppOrder = \[ws, l, _, wins] -> [ws, l, wins] , ppExtras = [logTitles formatFocused formatUnfocused] } where formatFocused = wrap (white "[") (white "]") . magenta . ppWindow formatUnfocused = wrap (lowWhite "[") (lowWhite "]") . blue . ppWindow -- | Windows should have *some* title, which should not not exceed a -- sane length. ppWindow :: String -> String ppWindow = xmobarRaw . (\w -> if null w then "untitled" else w) . shorten 30 blue, lowWhite, magenta, red, white, yellow :: String -> String magenta = xmobarColor "#ff79c6" "" blue = xmobarColor "#bd93f9" "" white = xmobarColor "#f8f8f2" "" yellow = xmobarColor "#f1fa8c" "" red = xmobarColor "#ff5555" "" lowWhite = xmobarColor "#bbbbbb" "" borderColor = "#8be9fd" myKeys :: [(String, X ())] myKeys = [ -- Screen lock & suspend ("C-M1-l" , spawn "i3lock" ) , ("C-M1-S-l" , spawn "i3lock" *> spawn "systemctl suspend") -- Terminal , ("M4-", spawn "kitty -1") -- Frequent programs , ("M4-q", spawn "firefox" ) , ("M4-a", runOrCopy "emacs" (className =? "Emacs")) , ("M4-d", spawn "discord" ) , ("M4-g", spawn "dolphin" ) -- Program launcher , ("M4-r", spawn "rofi -show drun -theme Paper" ) -- Exit , ("M4-M1-C-q", io (exitWith ExitSuccess) ) -- Manipulate current client , ("M4-w", kill1 ) , ("M4-s", toggleFloat ) -- focus client , ("M4-h", sendMessage (Go L) ) , ("M4-j", sendMessage (Go D) ) , ("M4-k", sendMessage (Go U) ) , ("M4-l", sendMessage (Go R) ) -- focus client (easymotion) , ("M4-;", selectWindow def >>= (`whenJust` windows . W.focusWindow)) -- Swap client , ("M4-S-h", sendMessage $ Swap L) , ("M4-S-j", sendMessage $ Swap D) , ("M4-S-k", sendMessage $ Swap U) , ("M4-S-l", sendMessage $ Swap R) , ("M4-S-", windows $ W.swapMaster) -- Move client , ("M4-M1-S-h", sendMessage (Move L) ) , ("M4-M1-S-j", sendMessage (Move D) ) , ("M4-M1-S-k", sendMessage (Move U) ) , ("M4-M1-S-l", sendMessage (Move R) ) -- Fullscreen , ("M4-f", sendMessage (Toggle FULL) ) -- Magnification , ("M4-m", sendMessage (Mag.Toggle) ) , ("M4-[", sendMessage (Mag.MagnifyLess) ) , ("M4-]", sendMessage (Mag.MagnifyMore) ) -- Modify number of master windows , ("M4-M1-j", sendMessage (IncMasterN (-1))) , ("M4-M1-k", sendMessage (IncMasterN 1 )) -- Resize master area , ("M4-C-h", sendMessage Shrink) , ("M4-C-l", sendMessage Expand) -- Cycle through workspaces , ("M4-", moveTo Prev spacesOnCurrentScreen ) , ("M4-", moveTo Next spacesOnCurrentScreen ) -- Cycle through empty workspaces , ("M4-M1-", moveTo Prev emptySpacesOnCurrentScreen) , ("M4-M1-", moveTo Next emptySpacesOnCurrentScreen) -- Send window through workspaces , ("M4-S-", shiftTo Prev spacesOnCurrentScreen ) , ("M4-S-", shiftTo Next spacesOnCurrentScreen ) -- Music player control (void) , ("", spawn "playerctl play-pause" ) , ("", spawn "playerctl previous" ) , ("", spawn "playerctl next" ) , ("", spawn "cmus-remote -C player-next-album") -- Music player control (t470) , ("", spawn "playerctl play-pause") , ("", spawn "playerctl previous") , ("", spawn "playerctl next") -- Potentially broken key , ("", spawn "cmus-remote -C player-next-album") -- Audio control , ("", spawn "wpctl set-mute @DEFAULT_SINK@ toggle") , ("", spawn "wpctl set-volume @DEFAULT_SINK@ 1%-") , ("", spawn "wpctl set-volume @DEFAULT_SINK@ 1%+") -- Mic control , ("", spawn "wpctl set-mute @DEFAULT_SOURCE@ toggle") , ("M1-", spawn "wpctl set-volume @DEFAULT_SOURCE@ 1%-") , ("M1-", spawn "wpctl set-volume @DEFAULT_SOURCE@ 1%+") -- backlight control (t470) , ("", spawn "brightnessctl set 1%-") , ("", spawn "brightnessctl set 1%+") -- backlight control (void) , ("M4-", spawn "ddcutil setvcp 10 + 10") , ("M4-", spawn "ddcutil setvcp 10 - 10") -- Reload configuration , ("M4-", spawn "xmonad --recompile; xmonad --restart") ] ++ concat [ -- Workspace switching [ ("M4-" ++ i, windows $ onCurrentScreen W.view $ i) -- Move window to workspace , ("M4-S-" ++ i, windows $ onCurrentScreen W.shift $ i) -- Copy window to workspace , ("M4-M1-S-" ++ i, windows $ onCurrentScreen copy $ i) ] | i <- myWorkspaceNames ] -- https://stackoverflow.com/questions/33547168/xmonad-combine-dwm-style-workspaces-per-physical-screen-with-cycling-function isOnScreen :: ScreenId -> WindowSpace -> Bool isOnScreen s ws = s == unmarshallS (W.tag ws) currentScreen :: X ScreenId currentScreen = gets (W.screen . W.current . windowset) spacesOnCurrentScreen :: WSType spacesOnCurrentScreen = WSIs (isOnScreen <$> currentScreen) emptySpacesOnCurrentScreen :: WSType emptySpacesOnCurrentScreen = spacesOnCurrentScreen :&: emptyWS myLayout = smartBorders $ windowNavigation $ mkToggle (single FULL) $ (Mag.magnifiercz' 1.3 $ ThreeColMid 1 (3/100) (2/3)) ||| Tall 1 (3/100) (2/3) -- https://www.reddit.com/r/xmonad/comments/hm2tg0/how_to_toggle_floating_state_on_a_window/ -- Centre and float a window (retain size) centreFloat win = do (_, W.RationalRect x y w h) <- floatLocation win windows $ W.float win (W.RationalRect ((1 - w) / 2) ((1 - h) / 2) w h) return () -- If the window is floating then (f), if tiled then (n) floatOrNot f n = withFocused $ \windowId -> do floats <- gets (W.floating . windowset) if windowId `M.member` floats -- if the current window is floating... then f else n -- Float and centre a tiled window, sink a floating window toggleFloat = floatOrNot (withFocused $ windows . W.sink) (withFocused float)