diff --git a/home/alex/home.nix b/home/alex/home.nix index 9f68cc7..e88d65b 100644 --- a/home/alex/home.nix +++ b/home/alex/home.nix @@ -4,6 +4,7 @@ imports = [ ./cli.nix ./programs/rofi + ./programs/xmonad ./services/polybar ./services/dunst ./services/udiskie diff --git a/home/alex/programs/xmonad/config.hs b/home/alex/programs/xmonad/config.hs new file mode 100644 index 0000000..7e262e6 --- /dev/null +++ b/home/alex/programs/xmonad/config.hs @@ -0,0 +1,146 @@ +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 emptyBSP Full + +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 + , 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-b", 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-r", WS.nextWS) + , -- scratchpads + ("M-s n", namedScratchpadAction scratchpads "notes") + , ("M-s s", namedScratchpadAction scratchpads "shell") + , -- backlight control + + ("", spawn "xbacklight -dec 5") + , ("", spawn "xbacklight -inc 5") + , ("", spawn "xbacklight -dec 5") + , ("", spawn "xbacklight -inc 5") + , -- volume control + + ("", changeVolume ToggleVolume) + , ("", changeVolume $ LowerVolume 5) + , ("", changeVolume $ RaiseVolume 5) + , ("M-a", sendMessage Balance) + , ("M-S-a", sendMessage Equalize) + , ("M-o", sendMessage Rotate) + ] + 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 +-- ] diff --git a/home/alex/programs/xmonad/default.nix b/home/alex/programs/xmonad/default.nix new file mode 100644 index 0000000..af59330 --- /dev/null +++ b/home/alex/programs/xmonad/default.nix @@ -0,0 +1,9 @@ +{ config, lib, pkgs, ... }: + +{ + config.xsession.windowManager.xmonad = { + enable = true; + enableContribAndExtras = true; + config = ./config.hs; + }; +}