nix/xmonad.hs

200 lines
8.8 KiB
Haskell
Raw Normal View History

2025-02-09 13:19:01 +01:00
import XMonad
import XMonad.Util.EZConfig
2025-02-27 14:48:50 +01:00
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
2025-02-09 13:19:01 +01:00
import System.Exit
2025-02-27 14:48:50 +01:00
import XMonad.Util.Loggers
2025-02-09 13:19:01 +01:00
2025-02-27 14:48:50 +01:00
-- 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-<Return>", 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-<Return>", 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-<Left>", moveTo Prev spacesOnCurrentScreen )
, ("M4-<Right>", moveTo Next spacesOnCurrentScreen )
-- Cycle through empty workspaces
, ("M4-M1-<Left>", moveTo Prev emptySpacesOnCurrentScreen)
, ("M4-M1-<Right>", moveTo Next emptySpacesOnCurrentScreen)
-- Send window through workspaces
, ("M4-S-<Left>", shiftTo Prev spacesOnCurrentScreen )
, ("M4-S-<Right>", shiftTo Next spacesOnCurrentScreen )
-- Music player control (void)
, ("<XF86AudioPlay>", spawn "playerctl play-pause" )
, ("<Scroll_Lock>", spawn "playerctl previous" )
, ("<XF86AudioNext>", spawn "playerctl next" )
, ("<Pause>", spawn "cmus-remote -C player-next-album")
-- Music player control (t470)
, ("<XF86Bluetooth>", spawn "playerctl play-pause")
, ("<XF86Tools>", spawn "playerctl previous")
, ("<XF86Keyboard>", spawn "playerctl next") -- Potentially broken key
, ("<XF86Favorites>", spawn "cmus-remote -C player-next-album")
-- Audio control
, ("<XF86AudioMute>", spawn "wpctl set-mute @DEFAULT_SINK@ toggle")
, ("<XF86AudioLowerVolume>", spawn "wpctl set-volume @DEFAULT_SINK@ 1%-")
, ("<XF86AudioRaiseVolume>", spawn "wpctl set-volume @DEFAULT_SINK@ 1%+")
-- Mic control
, ("<XF86AudioMicMute>", spawn "wpctl set-mute @DEFAULT_SOURCE@ toggle")
, ("M1-<XF86AudioLowerVolume>", spawn "wpctl set-volume @DEFAULT_SOURCE@ 1%-")
, ("M1-<XF86AudioRaiseVolume>", spawn "wpctl set-volume @DEFAULT_SOURCE@ 1%+")
-- backlight control (t470)
, ("<XF86MonBrightnessDown>", spawn "brightnessctl set 1%-")
, ("<XF86MonBrightnessUp>", spawn "brightnessctl set 1%+")
-- backlight control (void)
, ("M4-<Prior>", spawn "ddcutil setvcp 10 + 10")
, ("M4-<Next>", spawn "ddcutil setvcp 10 - 10")
-- Reload configuration
, ("M4-<Escape>", 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)