From 4196f7ac92c5ca1b973b0b3bedf7a337941baf66 Mon Sep 17 00:00:00 2001 From: Phil Bajsicki Date: Wed, 9 Aug 2023 20:31:55 +0200 Subject: [PATCH] XMonad: literate config: further breakdown into categories. --- .config/xmonad/README.org | 355 ++++++++++++++++++++++++++------------ 1 file changed, 240 insertions(+), 115 deletions(-) diff --git a/.config/xmonad/README.org b/.config/xmonad/README.org index f2d5364..6e3483c 100644 --- a/.config/xmonad/README.org +++ b/.config/xmonad/README.org @@ -2,42 +2,83 @@ #+author: Phil Bajsicki #+PROPERTY: header-args :tangle xmonad.hs -* Info: + +* Table of Contents :toc: +- [[#info][Info]] +- [[#imports][Imports]] + - [[#base][Base]] + - [[#actions][Actions]] + - [[#data][Data]] + - [[#hooks][Hooks]] + - [[#layouts][Layouts]] + - [[#layout-modifiers][Layout Modifiers]] + - [[#xmonadprompt][XMonad.Prompt]] + - [[#utilities][Utilities]] + - [[#colorschemes][Colorschemes]] +- [[#window-management-and-layouts][Window Management and Layouts]] + - [[#border-width-and-spacing][Border Width and Spacing]] + - [[#layouts-1][Layouts]] + - [[#theming-for-tabs-sublayout][Theming for tabs (sub)layout]] + - [[#clickable-workspaces-in-xmobar][Clickable workspaces in XMobar]] + - [[#workspace-definitions][Workspace definitions]] + - [[#manage-hook][Manage Hook]] + - [[#startup-hook][Startup Hook]] +- [[#main-xmonad-loop][Main XMonad loop]] + - [[#xmobar][XMobar]] + - [[#xmonad--managehook][XMonad & manageHook]] +- [[#keybinds][Keybinds]] + - [[#workspaces][Workspaces]] + - [[#window-focus-and-movement][Window focus and movement]] + - [[#sublayouts][Sublayouts]] + - [[#xmonad-and-apps][XMonad and apps]] + +* Info This is my XMonad config. It's heavily based on Derek Taylor's config from DTOS. +The notable things I changed are noted in their specific sections. + * Imports +** Base + #+begin_src haskell --- Base import XMonad import System.Directory import System.IO (hClose, hPutStr, hPutStrLn) import System.Exit (exitSuccess) import qualified XMonad.StackSet as W +#+end_src - -- Actions + +** Actions +#+begin_src haskell import XMonad.Actions.CopyWindow (kill1) import XMonad.Actions.CycleWS import XMonad.Actions.GridSelect import XMonad.Actions.MouseResize import XMonad.Actions.Promote import XMonad.Actions.RotSlaves (rotSlavesDown, rotAllDown) +import XMonad.Actions.SpawnOn import XMonad.Actions.UpdatePointer import XMonad.Actions.WindowGo (runOrRaise) import XMonad.Actions.WithAll (sinkAll, killAll) import qualified XMonad.Actions.Search as S +#+end_src - -- Data +** Data +#+begin_src haskell import Data.Char (isSpace, toUpper) import Data.Maybe (fromJust) import Data.Monoid import Data.Maybe (isJust) import Data.Tree import qualified Data.Map as M +#+end_src - -- Hooks +** Hooks +#+begin_src haskell 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.ManageDocks (avoidStruts, docks, manageDocks, ToggleStruts(..)) @@ -48,8 +89,10 @@ import XMonad.Hooks.StatusBar import XMonad.Hooks.StatusBar.PP import XMonad.Hooks.WindowSwallowing import XMonad.Hooks.WorkspaceHistory +#+end_src - -- Layouts +** Layouts +#+begin_src haskell import XMonad.Layout.Accordion import XMonad.Layout.GridVariants (Grid(Grid)) import XMonad.Layout.SimplestFloat @@ -57,8 +100,10 @@ import XMonad.Layout.Spiral import XMonad.Layout.ResizableTile import XMonad.Layout.Tabbed import XMonad.Layout.ThreeColumns +#+end_src - -- Layouts modifiers +** Layout Modifiers +#+begin_src haskell import XMonad.Layout.LayoutModifier import XMonad.Layout.LimitWindows (limitWindows, increaseLimit, decreaseLimit) import XMonad.Layout.MultiToggle (mkToggle, single, EOT(EOT), (??)) @@ -73,11 +118,17 @@ import XMonad.Layout.WindowArranger (windowArrange, WindowArrangerMsg(..)) import XMonad.Layout.WindowNavigation import qualified XMonad.Layout.ToggleLayouts as T (toggleLayouts, ToggleLayout(Toggle)) import qualified XMonad.Layout.MultiToggle as MT (Toggle(..)) +#+end_src +** XMonad.Prompt +#+begin_src haskell import XMonad.Prompt import XMonad.Prompt.OrgMode +#+end_src --- Utilities + +** Utilities +#+begin_src haskell import XMonad.Util.Dmenu import XMonad.Util.EZConfig import XMonad.Util.NamedActions @@ -85,40 +136,48 @@ import XMonad.Util.NamedScratchpad import XMonad.Util.Run (runProcessWithInput, safeSpawn, spawnPipe) import XMonad.Util.SpawnOnce import XMonad.Util.ClickableWorkspaces +#+end_src - -- ColorScheme module (SET ONLY ONE!) - -- Possible choice are: - -- DoomOne - -- Dracula - -- GruvboxDark - -- MonokaiPro - -- Nord - -- OceanicNext - -- Palenight - -- SolarizedDark - -- SolarizedLight - -- TomorrowNight +** Colorschemes +DT's ColorScheme module. Possible choice are: +- DoomOne +- Dracula +- GruvboxDark +- MonokaiPro +- Nord +- OceanicNext +- Palenight +- SolarizedDark +- SolarizedLight +- TomorrowNight + +#+begin_src haskell import Colors.DoomOne - #+end_src * Window Management and Layouts +** Border Width and Spacing #+begin_src haskell +myBorderWidth :: Dimension +myBorderWidth = 2 -myBorderWidth :: Dimension --used in 2 places -myBorderWidth = 2 -- Sets border width for windows - -windowCount :: X (Maybe String) --used in 2 places +windowCount :: X (Maybe String) windowCount = gets $ Just . show . length . W.integrate' . W.stack . W.workspace . W.current . windowset --Makes setting the spacingRaw simpler to write. The spacingRaw module adds a configurable amount of space around windows. mySpacing :: Integer -> l a -> XMonad.Layout.LayoutModifier.ModifiedLayout Spacing l a mySpacing i = spacingRaw False (Border i i i i) True (Border i i i i) True +#+end_src + + +** Layouts +- limitWindows n sets maximum number of windows displayed for layout. +- mySpacing n sets the gap size around the windows. + +#+begin_src haskell + --- Defining a bunch of layouts, many that I don't use. --- limitWindows n sets maximum number of windows displayed for layout. --- mySpacing n sets the gap size around the windows. tall = renamed [Replace "tall"] $ smartBorders -- $ windowNavigation @@ -137,37 +196,30 @@ tabs = renamed [Replace "tabs"] -- I cannot add spacing to this layout because it will -- add spacing between window and tabs which looks bad. $ tabbed shrinkText myTabTheme +#+end_src + +** Theming for tabs (sub)layout +#+begin_src haskell + --- setting colors for tabs layout and tabs sublayout. myTabTheme = def { fontName = "xft:Iosevka-9" , activeColor = color15 , inactiveColor = colorBack , activeBorderColor = color15 , inactiveBorderColor = colorFore , activeTextColor = colorBack - , inactiveTextColor = colorFore - } + , inactiveTextColor = colorFore } +#+end_src -myManageHook = composeAll - [ className =? "confirm" --> doFloat - , className =? "file_progress" --> doFloat - , className =? "dialog" --> doFloat - , className =? "download" --> doFloat - , className =? "error" --> doFloat - , className =? "Gimp" --> doFloat - , className =? "notification" --> doFloat - , className =? "pinentry-gtk-2" --> doFloat - , className =? "splash" --> doFloat - , className =? "toolbar" --> doFloat - , className =? "zoom" --> doFloat - , className =? "Yad" --> doCenterFloat - , (className =? "firefox" <&&> resource =? "Dialog") --> doFloat -- Float Firefox Dialog - , isFullscreen --> doFullFloat - ] --- myWorkspaceIndices = M.fromList $ zipWith (,) workspaces [1..] -- (,) == \x y -> (x,y) +** Clickable workspaces in XMobar +#+begin_src haskell mySB = statusBarProp "xmobar" (clickablePP xmobarPP) +#+end_src +** Workspace definitions + +#+begin_src haskell myWorkspaces = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "e", "w", "g", "d", "b", "j", "f", "o", "u", @@ -176,52 +228,118 @@ myWorkspaces = ["1", "2", "3", "4", "5", "6", "7", "8", "9", ] myWorkspaceIndices = M.fromList $ zipWith (,) myWorkspaces [1..] -- (,) == \x y -> (x,y) + clickable ws = ""++ws++"" where i = fromJust $ M.lookup ws myWorkspaceIndices - #+end_src +** Manage Hook +#+begin_src haskell +myManageHook = manageSpawn <> composeAll + [ className =? "confirm" --> doFloat + , className =? "file_progress" --> doFloat + , className =? "dialog" --> doFloat + , className =? "download" --> doFloat + , className =? "error" --> doFloat + , className =? "Gimp" --> doFloat + , className =? "notification" --> doFloat + , className =? "pinentry-gtk-2" --> doFloat + , className =? "splash" --> doFloat + , className =? "toolbar" --> doFloat + , className =? "zoom" --> doFloat + , className =? "Yad" --> doCenterFloat + , (className =? "firefox" <&&> resource =? "Dialog") --> doFloat -- Float Firefox Dialog + , isFullscreen --> doFullFloat + ] +#+end_src +** Startup Hook + +Set the WMName and session type so applications which check for it don't bug out. +*** Settings applied on login +#+begin_src haskell +myStartupHook = do + setWMName "LG3D" + spawnOnce "lxsession" +#+end_src +**** Keyboard layout +I'm Polish, so I type on a Polish layout. I also extensively use the compose key, so I have it handy. +#+begin_src haskell + spawnOnce "setxkbmap -model pc104 -layout pl -option compose:rctrl" +#+end_src +**** Mount encrypted container +#+begin_src haskell + spawnOnce "gocryptfs ~/.bajsicki enc --extpass lxqt-openssh-askpass" +#+end_src +**** Wallpaper +Randomize wallpaper. Requires /feh/. You can change the path to any directory with wallpapers for consistent variety. +#+begin_src haskell + spawnOnce "feh --randomize --bg-fill /usr/share/backgrounds/archlinux/*" +#+end_src +**** Trayer +Trayer is a system tray, which works well with XMobar. This restarts it every time XMonad is reinitialized to avoid weirdness. +#+begin_src haskell + spawn "killall trayer" -- kill current trayer on each + spawn ("sleep 2 && trayer --edge top --align right --widthtype request --padding 6 --SetDockType true --SetPartialStrut true --expand true --monitor 1 --transparent true --alpha 0 " ++ colorTrayer ++ " --height 20") +#+end_src + +**** Daemons +***** Dunst +Dunst for notifications. +#+begin_src haskell + spawnOnce "dunst" +#+end_src +***** Activity Watch +I like looking back on the way I spend my time every once in a while. Local time tracking is really helpful, so I run AW in the background. +#+begin_src haskell + spawnOnce "aw-server" + spawnOnce "aw-watcher-afk" + spawnOnce "aw-watcher-window" + spawnOnce "poetry run aw-watcher-spotify" +#+end_src +***** Emacs +Emacs daemon for emacsclient. +#+begin_src haskell + spawnOnce "/usr/bin/emacs --daemon" +#+end_src +*** Startup applications +#+begin_src haskell + spawnOn "1" "firefox-developer-edition" + spawnOn "2" "evolution" + spawnOn "9" "steam" + spawnOn "3" "discord" + spawnOn "6" "google-chrome-stable" + spawnOn "e" "/usr/bin/emacsclient" + spawnOn "j" "keepassxc" +#+end_src * Main XMonad loop #+begin_src haskell - - main :: IO () main = do - -- Launching three instances of xmobar on their monitors. +#+end_src +** XMobar +Launching three instances of xmobar on their monitors. +#+begin_src haskell xmproc0 <- spawnPipe ("xmobar -x 0 $HOME/.config/xmobar/tomorrow-night-xmobarrc") xmproc1 <- spawnPipe ("xmobar -x 1 $HOME/.config/xmobar/tomorrow-night-xmobarrc") xmproc2 <- spawnPipe ("xmobar -x 2 $HOME/.config/xmobar/tomorrow-night-xmobarrc") - -- the xmonad, ya know...what the WM is named after! + +#+end_src +** XMonad & manageHook +#+begin_src haskell xmonad $ ewmh $ docks $ def { manageHook = myManageHook <+> manageDocks +#+end_src +*** handleEventHook +This lets alacritty be swallowed when it opens a GUI application. +#+begin_src haskell , handleEventHook = swallowEventHook (className =? "Alacritty" <||> className =? "st-256color" <||> className =? "XTerm") (return True) - -- docks - -- Uncomment this line to enable fullscreen support on things like YouTube/Netflix. - -- This works perfect on SINGLE monitor systems. On multi-monitor systems, - -- it adds a border around the window if screen does not have focus. So, solution - -- is to use a keybinding to toggle fullscreen noborders instead. (M-) - -- <+> fullscreenEventHook +#+end_src +*** Pulling settings together +#+begin_src haskell , modMask = mod4Mask , terminal = "alacritty" - , startupHook = do - setWMName "LG3D" - spawnOnce "feh --randomize --bg-fill /usr/share/backgrounds/archlinux/*" -- feh set random wallpaper" - spawnOnce "lxsession" - spawnOnce "nm-applet" - spawnOnce "picom" - spawnOnce "volumeicon" - spawn "~/.screenalyout/3-laptop-center.sh" - spawn "setxkbmap -model pc104 -layout pl" - spawn "dunst" - spawnOnce "python tech/source/aw-watcher-spotify/aw_watcher_spotify/main.py" - spawnOnce "aw-watcher-afk" - spawnOnce "aw-watcher-window" - - spawn "killall conky" -- kill current conky on each restart - spawn "/usr/bin/emacs --daemon" -- emacs daemon for the emacsclient - spawn "killall trayer" -- kill current trayer on each - spawn ("sleep 2 && trayer --edge top --align right --widthtype request --padding 6 --SetDockType true --SetPartialStrut true --expand true --monitor 1 --transparent true --alpha 0 " ++ colorTrayer ++ " --height 20") + , startupHook = myStartupHook , layoutHook = avoidStruts $ windowNavigation $ subTabbed @@ -234,19 +352,26 @@ main = do , borderWidth = myBorderWidth , normalBorderColor = colorBack , focusedBorderColor = color15 +#+end_src +*** logHook +Define logHook. ppOutput streams into the three instances of XMobar. +#+begin_src haskell , logHook = dynamicLogWithPP xmobarPP - { ppOutput = \x -> hPutStrLn xmproc0 x -- xmobar on monitor 1 - >> hPutStrLn xmproc1 x -- xmobar on monitor 2 - >> hPutStrLn xmproc2 x -- xmobar on monitor 3 + { ppOutput = \x -> hPutStrLn xmproc0 x + >> hPutStrLn xmproc1 x + >> hPutStrLn xmproc2 x +#+end_src +**** Colors/ clicks +#+begin_src haskell , ppCurrent = xmobarColor color06 "" . wrap ("") "" - -- Visible but not current workspace , ppVisible = xmobarColor color06 "" . clickable - -- Hidden workspace , ppHidden = xmobarColor color05 "" . wrap ("") "" . clickable - -- Hidden workspaces (no windows) , ppHiddenNoWindows = xmobarColor color05 "" . clickable +#+end_src +**** Window Title, Separators, etc. +#+begin_src haskell -- Title of active window , ppTitle = xmobarColor colorFore "" . shorten 48 -- Separator character @@ -258,16 +383,14 @@ main = do -- order of things in xmobar , ppOrder = \(ws:l:t:ex) -> [ws,l]++ex++[t] } >> updatePointer (0.5, 0.5) (0.0, 0.0) } - #+end_src * Keybinds - +** Workspaces +This is the bulk of my changes. I use /a lot/ of workspaces. +They're all under two chords. M-s /shows/ a workspace, and M-t /throws/ a window to a workspace. Easy mnemonics, yay. #+begin_src haskell - `additionalKeysP` - --- subKeys "Switch to workspace" [ ("M-s 1", (windows $ W.greedyView $ myWorkspaces !! 0)) , ("M-s 2", (windows $ W.greedyView $ myWorkspaces !! 1)) , ("M-s 3", (windows $ W.greedyView $ myWorkspaces !! 2)) @@ -304,7 +427,6 @@ main = do , ("M-s z", (windows $ W.greedyView $ myWorkspaces !! 33)) , ("M-s p", (windows $ W.greedyView $ myWorkspaces !! 34)) - -- ^++^ subKeys "Throw to workspace" , ("M-t 1", (windows $ W.shift $ myWorkspaces !! 0)) , ("M-t 2", (windows $ W.shift $ myWorkspaces !! 1)) , ("M-t 3", (windows $ W.shift $ myWorkspaces !! 2)) @@ -341,7 +463,10 @@ main = do , ("M-t z", (windows $ W.shift $ myWorkspaces !! 33)) , ("M-t p", (windows $ W.shift $ myWorkspaces !! 34)) - +#+end_src +** Window focus and movement +Pretty self-explanatory. /ToggleStruts/ is fullscreen. /sinkAll/ tiles floating windows. +#+begin_src haskell , ("M-o", windows W.focusUp) , ("M-a", windows W.focusDown) @@ -357,21 +482,17 @@ main = do , ("M-.", nextScreen) , ("M-,", prevScreen) - -- Switch layouts , ("M-", sendMessage NextLayout) , ("M-f", sendMessage (MT.Toggle NBFULL) >> sendMessage ToggleStruts) - -- Window resizing , ("M-y", sendMessage Shrink) , ("M-l", sendMessage Expand) - -- , ("M-M1-j", addName "Shrink window vertically" $ sendMessage MirrorShrink) - -- , ("M-M1-k", addName "Expand window vertically" $ sendMessage MirrorExpand) - - -- Floating windows - -- ("M-f", addName "Toggle float layout" $ sendMessage (T.Toggle "floats")) - -- , ("M-S-t", addName "Sink a floating window" $ withFocused $ windows . W.sink) , ("M-b", sinkAll) +#+end_src +** Sublayouts +This lets me 'collect' windows into a tiled group if it starts getting crowded on the screen. +#+begin_src haskell -- Sublayouts -- This is used to push windows to tabbed sublayouts, or pull them out of it. , ("C-S-M1-n",sendMessage $ pullGroup L) @@ -383,50 +504,54 @@ main = do , ("C-S-M1-u", withFocused (sendMessage . UnMergeAll)) , ("C-S-M1-j", onGroup W.focusUp') , ("C-S-M1-y", onGroup W.focusDown') - - - -- XMonad and apps +#+end_src +** XMonad and apps +Notes: I use a ZSA Moonlander so a lot of the 4-5 key sequences are actually just two keys. +*** XMonad +#+begin_src haskell , ("C-M1-S-0", sequence_ [spawn "xmonad --restart", spawn "xmonad --recompile"]) , ("M-S-M1-C-0", io exitSuccess) , ("S-C-M1-q", kill1) , ("M-S-C-M1-q", killAll) - , ("M-S-", spawn "~/.local/bin/dm-run") , ("M-d", spawn "rofi -show drun") - +#+end_src +*** Some common keybinds: +#+begin_src haskell , ("M-e", spawn "emacsclient -c -a 'emacs'") , ("M-", spawn "alacritty") , ("M-S-", spawn "feh --randomize --bg-fill /usr/share/backgrounds/archlinux/*") , ("M-", spawn "dm-maim") , ("", spawn "flameshot gui") - -- ORG PROMPTS +#+end_src +*** XMonad.Prompt.OrgMode +#+begin_src haskell , ("M-c i", orgPrompt def "TODO" "~/enc/org/inbox.org") , ("M-c l", orgPromptPrimary def "LINK" "~/enc/org/inbox.org") , ("M-c n", orgPrompt def "NOTE" "~/enc/org/inbox.org") , ("M-c p", orgPromptRefile def "TODO" "~/enc/org/phil.org") - - -- , ("", spawn "maim -so | xclip -selection clipboard -t image/png") - +#+end_src +*** Timestamp chords +For local time, EST, and PST. +#+begin_src haskell -- Time! Timestamps! , ("M-w l", spawn "sleep 0.5 && xdotool type \"$(date +'%Y.%m.%d %H:%M:%S %Z')\"") , ("M-w e", spawn "sleep 0.5 && xdotool type \"$(TZ=America/New_York date +'%Y.%m.%d %H:%M:%S %Z')\"") , ("M-w m", spawn "sleep 0.5 && xdotool type \"$(TZ=America/Denver date +'%Y.%m.%d %H:%M:%S %Z')\"") - - -- Multimedia Keys +#+end_src +*** Multimedia keys +#+begin_src haskell , ("", spawn "mpc toggle") , ("", spawn "mpc prev") , ("", spawn "mpc next") , ("", spawn "amixer set Master toggle") , ("", spawn "pactl set-sink-volume \"bluez_output.E8_EE_CC_02_F6_8A.1\" -5%") , ("", spawn "pactl set-sink-volume \"bluez_output.E8_EE_CC_02_F6_8A.1\" +5%") - -- , ("", addName "Open home page" $ spawn (myBrowser ++ " https://www.youtube.com/c/DistroTube")) - , ("", spawn "dm-websearch") - , ("", runOrRaise "evolution" (resource =? "evolution")) - , ("", runOrRaise "qalculate-gtk" (resource =? "qalculate-gtk")) --- , ("", spawn "eject /dev/cdrom") ] +#+end_src +*** Mouse wheel to switch workspaces. +#+begin_src haskell `additionalMouseBindings` [ ((mod4Mask, button4), \w -> focus w >> prevWS) , ((mod4Mask, button5), \w -> focus w >> nextWS)] - #+end_src