#+TITLE: XMonad Config #+PROPERTY: header-args :tangle xmonad.hs * XMonad Config Xmonad is a dynamically tiling X11 window manager that is written and configured in Haskell. Official documentation: https://xmonad.org This is the xmonad configuration of Derek Taylor (DistroTube) My YouTube: http://www.youtube.com/c/DistroTube My GitLab: http://www.gitlab.com/dwt1/ This config was getting massively long, so I have made this a modular config that sources multiple config files. Look under the imports for "Custom" modules. Those are my config files and they can be found in: ~/.xmonad/lib/Custom Keep in mind, that my configs are purposely bloated with examples of what you can do with xmonad. It is written more as a study guide rather than a config that you should download and use. * IMPORTS These are Haskell modules that we must import so that we can use their functions later in the config. #+BEGIN_SRC haskell -- Custom (my personal configs) import Custom.MyGridMenu import Custom.MyKeys import Custom.MyLayouts import Custom.MyPrompts import Custom.MyScratchpads import Custom.MyTreeMenu import Custom.MyVariables -- Base import XMonad import Data.Monoid import System.IO (hPutStrLn) import XMonad.Actions.MouseResize -- Hooks import XMonad.Hooks.DynamicLog (dynamicLogWithPP, wrap, xmobarPP, xmobarColor, shorten, PP(..)) import XMonad.Hooks.EwmhDesktops -- for some fullscreen events, also for xcomposite in obs. import XMonad.Hooks.FadeInactive import XMonad.Hooks.ManageDocks (avoidStruts, docksEventHook, manageDocks, ToggleStruts(..)) import XMonad.Hooks.ManageHelpers (isFullscreen, doFullFloat) import XMonad.Hooks.ServerMode import XMonad.Hooks.SetWMName import XMonad.Hooks.WorkspaceHistory -- Utilities import XMonad.Util.EZConfig (additionalKeysP) import XMonad.Util.NamedScratchpad import XMonad.Util.Run (runProcessWithInput, safeSpawn, spawnPipe) import XMonad.Util.SpawnOnce #+END_SRC * AUTOSTART These are commands we want XMonad to execute on startup, such as running a compositor, setting our wallpaper, starting the emacs daemon, and starting our system tray and the applications that belong in it. #+BEGIN_SRC haskell myStartupHook :: X () myStartupHook = do spawnOnce "nitrogen --restore &" spawnOnce "picom &" spawnOnce "nm-applet &" spawnOnce "volumeicon &" spawnOnce "trayer --edge top --align right --widthtype request --padding 6 --SetDockType true --SetPartialStrut true --expand true --monitor 1 --transparent true --alpha 0 --tint 0x292d3e --height 22 &" spawnOnce "/usr/bin/emacs --daemon &" -- spawnOnce "kak -d -s mysession &" setWMName "LG3D" #+END_SRC * WORKSPACES My workspaces are clickable meaning that the mouse can be used to switch workspaces. This requires xdotool. You need to use UnsafeStdInReader instead of simply StdInReader in xmobar config so you can pass actions to it. Also, you will notice I add tags to the clickable workspaces to select from the additionalFonts that I have set in my xmobar configs. #+BEGIN_SRC haskell xmobarEscape :: String -> String xmobarEscape = concatMap doubleLts where doubleLts '<' = "<<" doubleLts x = [x] myWorkspaces :: [String] myWorkspaces = clickable . (map xmobarEscape) -- $ ["1", "2", "3", "4", "5", "6", "7", "8", "9"] $ ["dev", "www", "sys", "doc", "vbox", "chat", "mus", "vid", "gfx"] where clickable l = [ " " ++ ws ++ " " | (i,ws) <- zip [1..9] l, let n = i ] #+END_SRC * MANAGEHOOK Sets some rules for certain programs. Examples include forcing certain programs to always float, or to always appear on a certain workspace. Forcing programs to a certain workspace with a doShift requires xdotool if you are using clickable workspaces. You need the className or title of the program. Use xprop to get this info. #+BEGIN_SRC haskell myManageHook :: XMonad.Query (Data.Monoid.Endo WindowSet) myManageHook = composeAll -- using 'doShift ( myWorkspaces !! 7)' sends program to workspace 8! -- I'm doing it this way because otherwise I would have to write out -- the full name of my workspaces. [ className =? "obs" --> doShift ( myWorkspaces !! 7 ) , title =? "firefox" --> doShift ( myWorkspaces !! 1 ) , className =? "mpv" --> doShift ( myWorkspaces !! 7 ) , className =? "vlc" --> doShift ( myWorkspaces !! 7 ) , className =? "Gimp" --> doShift ( myWorkspaces !! 8 ) , className =? "Gimp" --> doFloat , title =? "Oracle VM VirtualBox Manager" --> doFloat , className =? "VirtualBox Manager" --> doShift ( myWorkspaces !! 4 ) , (className =? "firefox" <&&> resource =? "Dialog") --> doFloat -- Float Firefox Dialog ] <+> namedScratchpadManageHook myScratchPads #+END_SRC * LOGHOOK Sets opacity for inactive (unfocused) windows. I prefer to not use this feature so I've set opacity to 1.0. If you want opacity, set this to a value of less than 1 (such as 0.9 for 90% opacity). #+BEGIN_SRC haskell myLogHook :: X () myLogHook = fadeInactiveLogHook fadeAmount where fadeAmount = 1.0 #+END_SRC * MAIN This is the "main" of XMonad. This where everything in our configs comes together and works. #+BEGIN_SRC haskell main :: IO () main = do -- Launching three instances of xmobar on their monitors. xmproc0 <- spawnPipe "xmobar -x 0 /home/dt/.config/xmobar/xmobarrc0" xmproc1 <- spawnPipe "xmobar -x 1 /home/dt/.config/xmobar/xmobarrc2" xmproc2 <- spawnPipe "xmobar -x 2 /home/dt/.config/xmobar/xmobarrc1" -- the xmonad, ya know...what the WM is named after! xmonad $ ewmh def { manageHook = ( isFullscreen --> doFullFloat ) <+> myManageHook <+> manageDocks -- Run xmonad commands from command line with "xmonadctl command". Commands include: -- shrink, expand, next-layout, default-layout, restart-wm, xterm, kill, refresh, run, -- focus-up, focus-down, swap-up, swap-down, swap-master, sink, quit-wm. You can run -- "xmonadctl 0" to generate full list of commands written to ~/.xsession-errors. , handleEventHook = serverModeEventHookCmd <+> serverModeEventHook <+> serverModeEventHookF "XMONAD_PRINT" (io . putStrLn) <+> docksEventHook , modMask = myModMask , terminal = myTerminal , startupHook = myStartupHook , layoutHook = myLayoutHook , workspaces = myWorkspaces , borderWidth = myBorderWidth , normalBorderColor = myNormColor , focusedBorderColor = myFocusColor , logHook = workspaceHistoryHook <+> myLogHook <+> dynamicLogWithPP xmobarPP { ppOutput = \x -> hPutStrLn xmproc0 x >> hPutStrLn xmproc1 x >> hPutStrLn xmproc2 x , ppCurrent = xmobarColor "#c3e88d" "" . wrap "[" "]" -- Current workspace in xmobar , ppVisible = xmobarColor "#c3e88d" "" -- Visible but not current workspace , ppHidden = xmobarColor "#82AAFF" "" . wrap "*" "" -- Hidden workspaces in xmobar , ppHiddenNoWindows = xmobarColor "#c792ea" "" -- Hidden workspaces (no windows) , ppTitle = xmobarColor "#b3afc2" "" . shorten 60 -- Title of active window in xmobar , ppSep = " | " -- Separators in xmobar , ppUrgent = xmobarColor "#C45500" "" . wrap "!" "!" -- Urgent workspace , ppExtras = [windowCount] -- # of windows current workspace , ppOrder = \(ws:l:t:ex) -> [ws,l]++ex++[t] } } `additionalKeysP` myKeys #+END_SRC