mirror of
https://github.com/librephoenix/nixos-config
synced 2025-01-19 15:15:52 +05:30
893 lines
39 KiB
Org Mode
893 lines
39 KiB
Org Mode
#+title: Xmonad Config
|
|
#+author: Emmet
|
|
|
|
* XMonad Config
|
|
The main configuration file for XMonad is [[./xmonad.hs][~/.xmonad/xmonad.hs]].
|
|
** Imports
|
|
First I import a bunch of libraries:
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- IMPORTS
|
|
import qualified Data.Map as M
|
|
import Control.Monad as C
|
|
import Data.List
|
|
import Data.Monoid
|
|
import Data.Maybe (fromJust)
|
|
import Graphics.X11.ExtraTypes.XF86
|
|
import System.Exit
|
|
import System.IO
|
|
import XMonad
|
|
import XMonad.Actions.Navigation2D
|
|
import XMonad.Actions.SpawnOn
|
|
import XMonad.Actions.TiledWindowDragging
|
|
import XMonad.Actions.Warp
|
|
import XMonad.Actions.WindowNavigation
|
|
import XMonad.Actions.WithAll
|
|
import XMonad.Hooks.DynamicLog
|
|
import qualified XMonad.Hooks.EwmhDesktops as EWMHD
|
|
import XMonad.Hooks.FadeWindows
|
|
import XMonad.Hooks.ManageDocks
|
|
import XMonad.Hooks.RefocusLast
|
|
import XMonad.Hooks.ServerMode
|
|
import XMonad.Hooks.StatusBar
|
|
import XMonad.Hooks.StatusBar.PP
|
|
import XMonad.Layout.DraggingVisualizer
|
|
import XMonad.Layout.Dwindle
|
|
import XMonad.Layout.Fullscreen
|
|
import XMonad.Layout.Gaps
|
|
import XMonad.Layout.LayoutHints
|
|
import XMonad.Layout.LimitWindows
|
|
import XMonad.Layout.MouseResizableTile
|
|
import XMonad.Layout.Spacing
|
|
import XMonad.ManageHook
|
|
import qualified XMonad.StackSet as W
|
|
--import qualified DBus as D
|
|
--import qualified DBus.Client as D
|
|
import XMonad.Util.NamedScratchpad
|
|
import XMonad.Util.Run
|
|
import XMonad.Util.SpawnOnce
|
|
|
|
#+END_SRC
|
|
** Theme Setup
|
|
*** Custom Color Library Template
|
|
#+BEGIN_SRC haskell :tangle ./lib/Colors/Stylix.hs.mustache
|
|
module Colors.Stylix where
|
|
|
|
import XMonad
|
|
|
|
colorBg = "#{{base00-hex}}"
|
|
colorFg = "#{{base05-hex}}"
|
|
color01 = "#{{base01-hex}}" -- usually black
|
|
color02 = "#{{base08-hex}}" -- usually red
|
|
color03 = "#{{base0B-hex}}" -- usually green
|
|
color04 = "#{{base0A-hex}}" -- usually yellow
|
|
color05 = "#{{base0E-hex}}" -- usually blue
|
|
color06 = "#{{base0F-hex}}" -- usually magenta
|
|
color07 = "#{{base0D-hex}}" -- usually cyan
|
|
color08 = "#{{base07-hex}}" -- usually white
|
|
|
|
-- Select focus and secondary color
|
|
colorFocus = color02
|
|
colorSecondary = color07
|
|
|
|
#+END_SRC
|
|
*** Import Custom Color Library
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- setup color variables
|
|
import Colors.Stylix
|
|
|
|
#+END_SRC
|
|
** Settings
|
|
*** Border Color
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Border colors for unfocused and focused windows, respectively.
|
|
myNormalBorderColor, myFocusedBorderColor :: String
|
|
myNormalBorderColor = colorBg
|
|
myFocusedBorderColor = colorFocus
|
|
|
|
#+END_SRC
|
|
*** Default Apps
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Default apps
|
|
myTerminal, myBrowser :: String
|
|
myTerminal = "$TERM"
|
|
myBrowser = "$BROWSER"
|
|
myEditor = "$EDITOR"
|
|
mySpawnEditor = "$SPAWNEDITOR"
|
|
|
|
#+END_SRC
|
|
*** Mouse Focus
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Whether focus follows the mouse pointer.
|
|
myFocusFollowsMouse :: Bool
|
|
myFocusFollowsMouse = False
|
|
|
|
-- Whether clicking on a window to focus also passes the click to the window
|
|
myClickJustFocuses :: Bool
|
|
myClickJustFocuses = False
|
|
|
|
#+END_SRC
|
|
*** Border Width
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Width of the window border in pixels.
|
|
myBorderWidth :: Dimension
|
|
myBorderWidth = 3
|
|
|
|
#+END_SRC
|
|
*** Select Modkey
|
|
The default modkey is =mod1Mask= which is bound to left alt. =mod3Mask= can be used for right alt, but most people (including myself) simply use =mod4Mask= which is bound to the super key.
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Modmask
|
|
myModMask :: KeyMask
|
|
myModMask = mod4Mask
|
|
|
|
#+END_SRC
|
|
*** Workspaces
|
|
By default, workspaces are simply numeric strings ("1", "2", "3", etc..), but any strings can be used (i.e. "web", "irc", "code", etc..). I set workspace names with <fn=1>\x____</fn> where the blank spaces represent a [[https://www.nerdfonts.com/][nerd font symbol code]]. This works nicely because I have a Nerd Font as fn=1 in my [[XMobar][xmobar]], which renders the nerd font glyphs in xmobar.
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
myWorkspaces :: [String]
|
|
myWorkspaces =
|
|
[ "<fn=1>\xf15c¹</fn>", -- document icon for writing
|
|
"<fn=1>\xeb01 ²</fn>", -- globe icon for browsing
|
|
"<fn=1>\xf121³</fn>", -- dev icon for programming
|
|
"<fn=1>\xf0cb9 ⁴</fn>", -- music file icon for composition
|
|
"<fn=1>\xf1fc⁵</fn>", -- paint icon for art
|
|
"<fn=1>\xf0bdc ⁶</fn>", -- video icon for recording/editing
|
|
"<fn=1>\xf0d6⁷</fn>", -- money icon for finances
|
|
"<fn=1>\xf19d⁸</fn>", -- cap icon for teaching
|
|
"<fn=1>\xf11b⁹</fn>" -- gamepad icon for gaming
|
|
]
|
|
|
|
myWorkspaceIndices = M.fromList $ zipWith (,) myWorkspaces [1..] -- (,) == \x y -> (x,y)
|
|
|
|
clickable ws = "<action=xdotool key super+"++show i++">"++ws++"</action>"
|
|
where i = fromJust $ M.lookup ws myWorkspaceIndices
|
|
|
|
#+END_SRC
|
|
*** Scratchpads
|
|
Scratchpads are single applications that are normally not visible (in a workspace called "NSP"), but can be brought into the current workspace with a quick keybind. I find that this works really well for applications I use frequently for quick tasks, such as my terminal, password manager, email, and music player.
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Scratchpads
|
|
myScratchPads :: [NamedScratchpad]
|
|
myScratchPads =
|
|
[ NS "terminal" spawnTerm findTerm manageTerm,
|
|
NS "ranger" spawnRanger findRanger manageRanger,
|
|
NS "octave" spawnOctave findOctave manageOctave,
|
|
NS "btm" spawnBtm findBtm manageBtm,
|
|
NS "geary" spawnGeary findGeary manageGeary,
|
|
NS "helpmenu" spawnHelp findHelp manageHelp,
|
|
NS "musikcube" spawnMusikcube findMusikcube manageMusikcube,
|
|
NS "cal" spawnCal findCal manageCal,
|
|
NS "pavucontrol" spawnPavucontrol findPavucontrol managePavucontrol,
|
|
NS "discord" spawnDiscord findDiscord manageDiscord
|
|
]
|
|
where
|
|
spawnTerm = myTerminal ++ " --title scratchpad"
|
|
findTerm = title =? "scratchpad"
|
|
manageTerm = customFloating $ W.RationalRect l t w h
|
|
where
|
|
h = 0.9
|
|
w = 0.9
|
|
t = 0.95 - h
|
|
l = 0.95 - w
|
|
spawnRanger = "kitty --title ranger-scratchpad -e ranger"
|
|
findRanger = title =? "ranger-scratchpad"
|
|
manageRanger = customFloating $ W.RationalRect l t w h
|
|
where
|
|
h = 0.9
|
|
w = 0.9
|
|
t = 0.95 - h
|
|
l = 0.95 - w
|
|
spawnOctave = myTerminal ++ " --title octave-scratchpad -e octave"
|
|
findOctave = title =? "octave-scratchpad"
|
|
manageOctave = customFloating $ W.RationalRect l t w h
|
|
where
|
|
h = 0.5
|
|
w = 0.4
|
|
t = 0.75 - h
|
|
l = 0.70 - w
|
|
spawnBtm = myTerminal ++ " -o font.size=12 --title btm-scratchpad -e btm"
|
|
findBtm = title =? "btm-scratchpad"
|
|
manageBtm = customFloating $ W.RationalRect l t w h
|
|
where
|
|
h = 0.5
|
|
w = 0.4
|
|
t = 0.75 - h
|
|
l = 0.70 - w
|
|
spawnDiscord = "gtkcord4"
|
|
findDiscord = className =? "gtkcord4"
|
|
manageDiscord = customFloating $ W.RationalRect l t w h
|
|
where
|
|
h = 0.5
|
|
w = 0.4
|
|
t = 0.75 - h
|
|
l = 0.70 - w
|
|
spawnGeary = "geary"
|
|
findGeary = className =? "Geary"
|
|
manageGeary = customFloating $ W.RationalRect l t w h
|
|
where
|
|
h = 0.5
|
|
w = 0.4
|
|
t = 0.75 - h
|
|
l = 0.70 - w
|
|
spawnHelp = myTerminal ++ " --title xmonad_helpmenu -e w3m ~/.xmonad/helpmenu.txt"
|
|
findHelp = title =? "xmonad_helpmenu"
|
|
manageHelp = customFloating $ W.RationalRect l t w h
|
|
where
|
|
h = 0.9
|
|
w = 0.9
|
|
t = 0.95 - h
|
|
l = 0.95 - w
|
|
spawnMusikcube = myTerminal ++ " -o font.size=14 --title musikcube-scratchpad -e musikcube"
|
|
findMusikcube = title =? "musikcube-scratchpad"
|
|
manageMusikcube = customFloating $ W.RationalRect l t w h
|
|
where
|
|
h = 0.9
|
|
w = 0.9
|
|
t = 0.95 - h
|
|
l = 0.95 - w
|
|
spawnCal = "gnome-calendar"
|
|
findCal = className =? "gnome-calendar"
|
|
manageCal = customFloating $ W.RationalRect l t w h
|
|
where
|
|
h = 0.4
|
|
w = 0.3
|
|
t = 0.45 - h
|
|
l = 1 - w
|
|
spawnPavucontrol = "pavucontrol"
|
|
findPavucontrol = className =? "Pavucontrol"
|
|
managePavucontrol = customFloating $ W.RationalRect l t w h
|
|
where
|
|
h = 0.5
|
|
w = 0.3
|
|
t = 0.9 - h
|
|
l = 0.65 - w
|
|
|
|
#+END_SRC
|
|
*** Keybindings
|
|
Keybinds can be set with an array of values like: =(keybind, action)=. The array is declared like so:
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
myKeys conf@(XConfig {XMonad.modMask = modm}) =
|
|
M.fromList $
|
|
[
|
|
-- insert keybinds with array values of ((keybind, action))
|
|
|
|
#+END_SRC
|
|
Then, keybindings are setup line by line as in the following sections:
|
|
**** Quick App Keybindings
|
|
The following binds the following:
|
|
| Keybinding | Action |
|
|
|---------------------+-----------------------------------------------|
|
|
| S-Return | New terminal |
|
|
| S-a | New emacs frame |
|
|
| S-s | New browser window |
|
|
| PrintScreen | Snip a screenshot |
|
|
| C-PrintScreen | Snip a screenshot (to clipboard) |
|
|
| Shift-PrintScreen | Screen capture current monitor |
|
|
| Shift-C-PrintScreen | Screen capture current monitor (to clipboard) |
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- launch a terminal
|
|
((modm, xK_Return), spawn $ XMonad.terminal conf),
|
|
|
|
-- launch emacsclient
|
|
((modm, xK_a), spawn mySpawnEditor),
|
|
|
|
-- launch browser
|
|
((modm, xK_s), spawn myBrowser),
|
|
|
|
-- take screenshots
|
|
((0, xK_Print), spawn "flameshot gui"), -- snip screenshot and save
|
|
((controlMask, xK_Print), spawn "flameshot gui --clipboard"), -- snip screenshot to clipboard
|
|
((shiftMask, xK_Print), spawn "flameshot screen"), -- screen capture current monitor and save
|
|
((controlMask .|. shiftMask, xK_Print), spawn "flameshot screen -c"), -- screen capture current monitor to clipboard
|
|
|
|
-- launch game manager in gaming workspace
|
|
((modm, xK_g), spawn "xdotool key Super+9 && gamehub"),
|
|
|
|
#+END_SRC
|
|
**** Generic Keybindings
|
|
These setup standard bindings for brightness and audio control from the keyboard.
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- control brightness from kbd
|
|
((0, xF86XK_MonBrightnessUp), spawn "brightnessctl set +15"),
|
|
((0, xF86XK_MonBrightnessDown), spawn "brightnessctl set 15-"),
|
|
|
|
-- control kbd brightness from kbd
|
|
((0, xF86XK_KbdBrightnessUp), spawn "brightnessctl --device='asus::kbd_backlight' set +1 & xset r rate 350 100"),
|
|
((0, xF86XK_KbdBrightnessDown), spawn "brightnessctl --device='asus::kbd_backlight' set 1- & xset r rate 350 100"),
|
|
((shiftMask, xF86XK_MonBrightnessUp), spawn "brightnessctl --device='asus::kbd_backlight' set +1 & xset r rate 350 100"),
|
|
((shiftMask, xF86XK_MonBrightnessDown), spawn "brightnessctl --device='asus::kbd_backlight' set 1- & xset r rate 350 100"),
|
|
|
|
-- control volume from kbd
|
|
((0, xF86XK_AudioLowerVolume), spawn "pamixer -d 10"),
|
|
((0, xF86XK_AudioRaiseVolume), spawn "pamixer -i 10"),
|
|
((0, xF86XK_AudioMute), spawn "pamixer -t"),
|
|
|
|
-- control music from kbd
|
|
--((0, xF86XK_AudioPlay), spawn "cmus-remote -u"),
|
|
--((0, xF86XK_AudioStop), spawn "cmus-remote -s"),
|
|
--((0, xF86XK_AudioNext), spawn "cmus-remote -n && ~/.local/bin/cmus-current-song-notify.sh"),
|
|
--((0, xF86XK_AudioPrev), spawn "cmus-remote -r && ~/.local/bin/cmus-current-song-notify.sh"),
|
|
|
|
#+END_SRC
|
|
**** Launcher Keybinds
|
|
I have =rofi= bound to =S-;= for quick app access.
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- launch rofi
|
|
((modm, xK_semicolon), spawn ("rofi -show drun -show-icons")),
|
|
((modm, xK_p), spawn ("keepmenu")),
|
|
((modm, xK_i), spawn ("networkmanager_dmenu")),
|
|
|
|
#+END_SRC
|
|
**** Window Management Keybinds
|
|
All of the following keybinds pertain to window management and layouts:
|
|
| Keybinding | Action |
|
|
|-------------------+------------------------------------------------------------------------------------------------|
|
|
| S-q | Kill window |
|
|
| S-Shift-c | Kill all windows on current workspace |
|
|
| S-Shift-q | Exit xmonad |
|
|
| S-Shift-Escape | Lock xmonad |
|
|
| S-Shift-s | Lock xmonad and suspend |
|
|
| S-Shift-Escape | Lock xmonad and suspend |
|
|
| S-Space | Switch to next layout |
|
|
| S-Shift-Space | Reset layout on current workspace |
|
|
| S-r | Resize windows to correct size |
|
|
| S-{←,↓,↑,→} | Switch to screen visually {left,down,up,right} (requires a [[Window Rules and Hooks][Navigation2Dconfig]]) |
|
|
| S-{h,j,k,l} | Switch to window visually {left,down,up,right} (requires a [[Window Rules and Hooks][Navigation2Dconfig]]) |
|
|
| S-Shift-{h,j,k,l} | Swap window visually {left,down,up,right} on current workspace (requires a [[Window Rules and Hooks][Navigation2Dconfig]]) |
|
|
| S-C-{h,l} | Resize master window area |
|
|
| S-m | Move current window into master window area |
|
|
| S-t | Toggle floating status of a window (this is a function defined [[Toggle Float Function Definition][here]]) |
|
|
| S-, | Increase number of windows in the master window area |
|
|
| S-. | Decrease number of windows in the master window area |
|
|
These keybindings are then set via:
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- close focused window
|
|
((modm, xK_q), kill),
|
|
-- close all windows on current workspace
|
|
((modm .|. shiftMask, xK_c), killAll),
|
|
-- exit xmonad
|
|
((modm .|. shiftMask, xK_q), spawn "killall xmonad-x86_64-linux"),
|
|
-- Lock with dm-tool
|
|
((modm, xK_Escape), spawn "dm-tool switch-to-greeter"),
|
|
-- Lock with dm-tool and suspend
|
|
((modm .|. shiftMask, xK_s), spawn "dm-tool switch-to-greeter & systemctl suspend"),
|
|
((modm .|. shiftMask, xK_Escape), spawn "dm-tool switch-to-greeter & systemctl suspend"),
|
|
|
|
-- Rotate through the available layout algorithms
|
|
((modm, xK_space), sendMessage NextLayout),
|
|
-- Reset the layouts on the current workspace to default
|
|
((modm .|. shiftMask, xK_space), setLayout $ XMonad.layoutHook conf),
|
|
|
|
-- Resize viewed windows to the correct size
|
|
((modm, xK_r), C.sequence_ [spawn "killall xmobar; autorandr -c; xmonad --restart;", refresh]),
|
|
|
|
-- Move focus to window below
|
|
((modm, xK_j), C.sequence_ [windowGo D True, switchLayer, warpToWindow 0.5 0.5]),
|
|
-- Move focus to window above
|
|
((modm, xK_k), C.sequence_ [windowGo U True, switchLayer, warpToWindow 0.5 0.5]),
|
|
-- Move focus to window left
|
|
((modm, xK_h), C.sequence_ [windowGo L True, switchLayer, warpToWindow 0.5 0.5]),
|
|
-- Move focus to window right
|
|
((modm, xK_l), C.sequence_ [windowGo R True, switchLayer, warpToWindow 0.5 0.5]),
|
|
|
|
-- Move focus to screen below
|
|
((modm, xK_Down), C.sequence_ [screenGo D True, warpToCurrentScreen 0.5 0.5]),
|
|
-- Move focus to screen up
|
|
((modm, xK_Up), C.sequence_ [screenGo U True, warpToCurrentScreen 0.5 0.5]),
|
|
-- Move focus to screen left
|
|
((modm, xK_Left), C.sequence_ [screenGo L True, warpToCurrentScreen 0.5 0.5]),
|
|
-- Move focus to screen right
|
|
((modm, xK_Right), C.sequence_ [screenGo R True, warpToCurrentScreen 0.5 0.5]),
|
|
|
|
-- Swap with window below
|
|
((modm .|. shiftMask, xK_j), C.sequence_ [windowSwap D True, windowGo U True, switchLayer]),
|
|
-- Swap with window above
|
|
((modm .|. shiftMask, xK_k), C.sequence_ [windowSwap U True, windowGo D True, switchLayer]),
|
|
-- Swap with window left
|
|
((modm .|. shiftMask, xK_h), C.sequence_ [windowSwap L True, windowGo R True, switchLayer]),
|
|
-- Swap with window right
|
|
((modm .|. shiftMask, xK_l), C.sequence_ [windowSwap R True, windowGo L True, switchLayer]),
|
|
|
|
-- Shrink the master area
|
|
((modm .|. controlMask, xK_h), sendMessage Shrink),
|
|
-- Expand the master area
|
|
((modm .|. controlMask, xK_l), sendMessage Expand),
|
|
|
|
-- Swap the focused window and the master window
|
|
((modm, xK_m), windows W.swapMaster),
|
|
|
|
-- Toggle tiling/floating status of window
|
|
((modm, xK_t), withFocused toggleFloat),
|
|
|
|
-- Increment the number of windows in the master area
|
|
((modm, xK_comma), sendMessage (IncMasterN 1)),
|
|
-- Deincrement the number of windows in the master area
|
|
((modm, xK_period), sendMessage (IncMasterN (-1))),
|
|
|
|
#+END_SRC
|
|
**** Scratchpad Keybinds
|
|
I have each [[Scratchpads][scratchpad]] bound to a keybinding for quick access:
|
|
| Keybinding | Associated Scratchpad |
|
|
|------------+----------------------------|
|
|
| S-f | Ranger file manager |
|
|
| S-x | KeePassXC password manager |
|
|
| S-z | Terminal |
|
|
| S-b | Bottom control panel |
|
|
| S-d | Discord |
|
|
| S-o | Octave (calculator) |
|
|
| S-e | mu4e (email) |
|
|
| S-n | Music player |
|
|
| S-c | cfw (calendar) |
|
|
| S-y | Pavucontrol (audio mixer) |
|
|
| S-/ | Keybinding help menu |
|
|
These are then bound:
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- scratchpad keybindings
|
|
((modm, xK_f), namedScratchpadAction myScratchPads "ranger"),
|
|
--((modm, xK_x), namedScratchpadAction myScratchPads "keepassxc"),
|
|
((modm, xK_z), namedScratchpadAction myScratchPads "terminal"),
|
|
((modm, xK_b), namedScratchpadAction myScratchPads "btm"),
|
|
((modm, xK_d), namedScratchpadAction myScratchPads "discord"),
|
|
((modm, xK_o), namedScratchpadAction myScratchPads "octave"),
|
|
((modm, xK_e), namedScratchpadAction myScratchPads "geary"),
|
|
((modm, xK_n), namedScratchpadAction myScratchPads "musikcube"),
|
|
((modm, xK_c), namedScratchpadAction myScratchPads "cal"),
|
|
((modm, xK_y), namedScratchpadAction myScratchPads "pavucontrol"),
|
|
((modm, xK_slash), namedScratchpadAction myScratchPads "helpmenu")
|
|
|
|
#+END_SRC
|
|
**** End of Standard Keybinds
|
|
To finish the section of standard keybinds, we simply close the array [[Keybindings][started above]].
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
]
|
|
#+END_SRC
|
|
**** Workspace Management Keybinds
|
|
Workspaces are generically managed via =mod-[1..9]= to shift to a workspace, and =mod-shift-[1..9]= to send a window to another workspace. To generate this effect, the following code is added to the keybindings definition:
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
++
|
|
-- mod-[1..9], Switch to workspace N
|
|
-- mod-shift-[1..9], Move client to workspace N
|
|
|
|
[ ((m .|. modm, k), windows $ f i)
|
|
| (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9],
|
|
(f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]
|
|
]
|
|
|
|
#+END_SRC
|
|
**** Custom Function Definitions
|
|
To have =toggleFloat= and =warpToCurrentScreen=, I must define them after setting up the keybinds like so:
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
where
|
|
-- toggle float/tiling status of current window
|
|
toggleFloat w =
|
|
windows
|
|
( \s ->
|
|
if M.member w (W.floating s)
|
|
then W.sink w s
|
|
else (W.float w (W.RationalRect (1 / 8) (1 / 8) (3 / 4) (3 / 4)) s)
|
|
)
|
|
-- warp cursor to (x, y) coordinate of current screen
|
|
warpToCurrentScreen x y = do
|
|
sid <- withWindowSet $ return . W.screen . W.current
|
|
warpToScreen sid x y
|
|
-- TODO goto and warp (coords x, y) to window in DIRECTION, or goto and warp (coords x, y) to screen in DIRECTION if no window is available
|
|
windowOrScreenGoAndWarp direction x y =
|
|
do windowGo direction True
|
|
|
|
#+END_SRC
|
|
**** Mouse Bindings
|
|
The following code sets up some convenient mouse bindings:
|
|
| Mouse Binding | Action |
|
|
|---------------+----------------------------------------------|
|
|
| S-Left click | Make window floating and drag to move window |
|
|
| S-Right click | Make window floating and resize window |
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Mouse bindings: default actions bound to mouse events
|
|
myMouseBindings (XConfig {XMonad.modMask = modm}) =
|
|
M.fromList $
|
|
-- -- mod-button1, Set the window to floating mode and move by dragging
|
|
[ ( (modm, button1),
|
|
( \w ->
|
|
focus w
|
|
>> mouseMoveWindow w
|
|
>> windows W.shiftMaster
|
|
)
|
|
),
|
|
-- mod-button3, Set the window to floating mode and resize by dragging
|
|
( (modm, button3),
|
|
( \w ->
|
|
focus w
|
|
>> mouseResizeWindow w
|
|
>> windows W.shiftMaster
|
|
)
|
|
)
|
|
-- you may also bind events to the mouse scroll wheel (button4 and button5)
|
|
]
|
|
|
|
#+END_SRC
|
|
*** Layouts
|
|
By default, I utilize three layouts:
|
|
- =mouseResizable= which is a master/stack layout I have set up to have dwindling sizes
|
|
- =mouseResizableMirrored=, same as above except mirrored
|
|
- =Full= where only one window takes up the entire space of the screen
|
|
|
|
I embellish these layouts with a few modifiers:
|
|
- =fullscreenFocus= for fullscreen support (also requires a [[Window Rules][fullscreen manage hook]])
|
|
- =draggingVisualizer= so that I can drag tiling windows about via my [[Mouse Bindings][mouse bindings]]
|
|
- =avoidStruts= since I use [[XMobar][xmobar]]
|
|
- =spacingRaw= to put a few pixels of space between windows since it looks nice
|
|
|
|
This is all applied in the following code to set the =myLayout= variable, which gets used later in the [[Main][main function]]:
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Layouts:
|
|
|
|
spcPx = 5
|
|
|
|
mySpacing = spacingRaw False (Border spcPx spcPx spcPx spcPx) True (Border spcPx spcPx spcPx spcPx) True
|
|
|
|
myLayout = fullscreenFocus $ draggingVisualizer $ avoidStruts $ layoutHintsToCenter $ (mySpacing $ (Full ||| mouseResizable ||| mouseResizableMirrored))
|
|
where
|
|
-- default tiling algorithm partitions the screen into two panes
|
|
tiled = Tall 1 (5 / 100) (1 / 2)
|
|
|
|
dwindled = Dwindle R CW 1.1 1.1
|
|
|
|
mouseResizable =
|
|
mouseResizableTile
|
|
{ masterFrac = 0.51,
|
|
slaveFrac = 0.51,
|
|
draggerType = BordersDragger
|
|
}
|
|
|
|
mouseResizableMirrored =
|
|
mouseResizableTile
|
|
{ masterFrac = 0.51,
|
|
slaveFrac = 0.51,
|
|
draggerType = BordersDragger,
|
|
isMirrored = True
|
|
}
|
|
|
|
#+END_SRC
|
|
*** Window Rules and Hooks
|
|
Window rules apply actions when a new window matching a specific query is apprehended by xmonad. I mainly use these to control my scratchpads (to make them all floating) and for some apps that don't behave nicely inside of a tiling window manager.
|
|
|
|
The easiest way to do a query is by either =className= or =title= which can both be found using =xprop=.
|
|
|
|
The list of window rules must be made into a manage hook, which gets used in the [[Main][main function]] when starting xmonad.
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Window rules:
|
|
myManageHook =
|
|
composeAll
|
|
[ title =? "Myuzi" --> (customFloating $ W.RationalRect 0.05 0.05 0.9 0.9),
|
|
title =? "octave-scratchpad" --> (customFloating $ W.RationalRect 0.1 0.1 0.8 0.8),
|
|
title =? "scratchpad" --> (customFloating $ W.RationalRect 0.1 0.1 0.8 0.8),
|
|
className =? "gtkcord4" --> (customFloating $ W.RationalRect 0.1 0.1 0.8 0.8),
|
|
title =? "ranger-scratchpad" --> (customFloating $ W.RationalRect 0.05 0.05 0.9 0.9),
|
|
title =? "btm-scratchpad" --> (customFloating $ W.RationalRect 0.1 0.1 0.8 0.8),
|
|
className =? "Geary" --> (customFloating $ W.RationalRect 0.05 0.05 0.9 0.9),
|
|
title =? "scratch_cfw" --> (customFloating $ W.RationalRect 0.58 0.04 0.42 0.7),
|
|
title =? "xmonad_helpmenu" --> (customFloating $ W.RationalRect 0.05 0.05 0.9 0.9),
|
|
className =? "Pavucontrol" --> (customFloating $ W.RationalRect 0.05 0.04 0.5 0.35),
|
|
className =? "Syncthing GTK" --> (customFloating $ W.RationalRect 0.53 0.50 0.46 0.45),
|
|
className =? "Proton Mail Bridge" --> (customFloating $ W.RationalRect 0.59 0.66 0.40 0.30),
|
|
className =? "Zenity" --> (customFloating $ W.RationalRect 0.45 0.4 0.1 0.2),
|
|
resource =? "desktop_window" --> doIgnore,
|
|
-- this gimp snippet is from Kathryn Anderson (https://xmonad.haskell.narkive.com/bV34Aiw3/layout-for-gimp-how-to)
|
|
(className =? "Gimp" <&&> fmap ("color-selector" `isSuffixOf`) role) --> doFloat,
|
|
(className =? "Gimp" <&&> fmap ("layer-new" `isSuffixOf`) role) --> doFloat,
|
|
(className =? "Gimp" <&&> fmap ("-dialog" `isSuffixOf`) role) --> doFloat,
|
|
(className =? "Gimp" <&&> fmap ("-tool" `isSuffixOf`) role) --> doFloat,
|
|
-- end snippet
|
|
resource =? "kdesktop" --> doIgnore,
|
|
manageDocks
|
|
]
|
|
where role = stringProperty "WM_WINDOW_ROLE"
|
|
|
|
#+END_SRC
|
|
|
|
I also must set my fullscreen manage hook and fullscreen event hook here to fully enable fullscreen support mentioned [[Layouts][earlier]]:
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Apply fullscreen manage and event hooks
|
|
myFullscreenManageHook = fullscreenManageHook
|
|
myFullscreenEventHook = fullscreenEventHook
|
|
|
|
#+END_SRC
|
|
|
|
Next, I set up my event hook to put xmonad into server mode, which allows me to use [[https://github.com/xmonad/xmonad-contrib/blob/master/scripts/xmonadctl.hs][xmonadctl]] from [[https://github.com/xmonad/xmonad-contrib][xmonad-contrib]], which enables control of xmonad actions from the shell/scripts.
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Server mode event hook
|
|
myEventHook = serverModeEventHook
|
|
|
|
#+END_SRC
|
|
|
|
Next I set up a =navigation2DConfig= for use with [[Window Management Keybinds][visual window movement]]:
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- navigation 2d config required for visual window movement
|
|
myNavigation2DConfig = def {layoutNavigation = [("Tall", hybridOf sideNavigation $ hybridOf centerNavigation lineNavigation), ("Full", hybridOf sideNavigation centerNavigation)]
|
|
, floatNavigation = hybridOf lineNavigation centerNavigation
|
|
, screenNavigation = hybridOf lineNavigation centerNavigation}
|
|
|
|
#+END_SRC
|
|
|
|
*** New Xmobar Setup
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
--myPP = def { ppCurrent = xmobarColor colorFocus "" }
|
|
myPP = xmobarPP { ppTitle = xmobarColor colorFocus "",
|
|
ppCurrent = xmobarStripTags ["NSP"] . xmobarColor colorFocus "",
|
|
ppVisible = xmobarStripTags ["NSP"] . xmobarColor colorSecondary "",
|
|
ppHidden = xmobarStripTags ["NSP"] . xmobarColor colorFg "",
|
|
ppHiddenNoWindows = xmobarStripTags ["NSP"] . xmobarColor color01 "",
|
|
ppOrder = \(ws : _) -> [ws],
|
|
ppSep = " "
|
|
}
|
|
mySB = statusBarProp "xmobar" (pure myPP)
|
|
|
|
#+END_SRC
|
|
*** Startup Script
|
|
I have a startup script at =~/.xmonad/startup.sh= which starts various apps and sets up a few things. In my xmonad config, it is autostarted by setting a =startupHook=.
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Startup hook
|
|
myStartupHook = do
|
|
spawnOnce ("~/.config/xmonad/startup.sh '" ++ colorBg ++ "' '" ++ colorFg ++ "' '" ++ colorFocus ++ "' '" ++ colorSecondary ++ "'")
|
|
|
|
#+END_SRC
|
|
|
|
First I start by retrieving the colors passed to the script from xmonad.
|
|
#+BEGIN_SRC sh :tangle startup.sh :tangle-mode (identity #o755)
|
|
colorBg=$1
|
|
colorFg=$2
|
|
colorFocus=$3
|
|
colorSecondary=$4
|
|
|
|
#+END_SRC
|
|
|
|
The autostart script kills all applications I am autostarting, which prevents multiple instances of background applications when I restart xmonad:
|
|
#+BEGIN_SRC sh :tangle startup.sh :tangle-mode (identity #o755)
|
|
# Startup shell script called by xmonad to start necessary programs
|
|
#
|
|
## Kill previous instances of applications (Prevents multiple instances of the following if XMonad is restarted durin the X session)
|
|
killall xmobar
|
|
killall nm-applet
|
|
|
|
#+END_SRC
|
|
|
|
Then, desktop applications are started in the background.
|
|
#+BEGIN_SRC sh :tangle startup.sh :tangle-mode (identity #o755)
|
|
# Launch necessary desktop applications
|
|
autorandr;
|
|
picom --animations --animation-window-mass 1 --animation-for-open-window zoom --animation-stiffness 200 --experimental-backends && # requires picom-pijulius
|
|
xset r rate 350 50 &
|
|
setxkbmap -option caps:escape &
|
|
~/.fehbg-stylix &
|
|
~/.config/xmobar/xmobar-st-check.sh &
|
|
alttab -w 1 -t 240x160 -i 64x64 -sc 1 -bg $colorBg -fg $colorFg -frame $colorSecondary -inact $colorFg &
|
|
##/usr/bin/trayer --edge top --align right --SetDockType true --SetPartialStrut true --expand true --widthtype request --transparent true --alpha 0 --height 28 --tint $trayertint --monitor "primary" &
|
|
nm-applet &
|
|
GOMAXPROCS=1 syncthing --no-browser &
|
|
protonmail-bridge --noninteractive &
|
|
emacs --daemon &
|
|
gnome-keyring-daemon --daemonize --login &
|
|
gnome-keyring-daemon --start --components=secrets &
|
|
#+END_SRC
|
|
** Main
|
|
Lastly, xmonad is started with all of the [[Settings][settings set up as variables]]. First xmobar is setup with =spawnPipe= so that it has access to the [[Workspaces][workspaces from xmonad]]. Then xmonad is executed with the settings.
|
|
#+BEGIN_SRC haskell :tangle xmonad.hs
|
|
-- Now run xmonad with all the defaults we set up.
|
|
main = do
|
|
spawn ("xmobar -x 0")
|
|
spawn ("xmobar -x 1")
|
|
spawn ("xmobar -x 2")
|
|
xmonad . withSB mySB $
|
|
withNavigation2DConfig myNavigation2DConfig $
|
|
fullscreenSupportBorder $
|
|
docks $
|
|
EWMHD.ewmh
|
|
def
|
|
{ -- simple stuff
|
|
terminal = myTerminal,
|
|
focusFollowsMouse = myFocusFollowsMouse,
|
|
clickJustFocuses = myClickJustFocuses,
|
|
borderWidth = myBorderWidth,
|
|
modMask = myModMask,
|
|
workspaces = myWorkspaces,
|
|
normalBorderColor = myNormalBorderColor,
|
|
focusedBorderColor = myFocusedBorderColor,
|
|
-- key bindings
|
|
keys = myKeys,
|
|
mouseBindings = myMouseBindings,
|
|
-- hooks, layouts
|
|
layoutHook = myLayout,
|
|
manageHook = myManageHook <+> myFullscreenManageHook <+> namedScratchpadManageHook myScratchPads,
|
|
handleEventHook = myEventHook <+> myFullscreenEventHook <+> fadeWindowsEventHook,
|
|
logHook = (refocusLastLogHook >> nsHideOnFocusLoss myScratchPads),
|
|
startupHook = myStartupHook
|
|
}
|
|
#+END_SRC
|
|
* XMobar Config
|
|
I utilize xmobar as a status bar on my monitors. To manage my xmobar config, I start by creating a template file, and then style that using stylix.
|
|
** Xmobar Template
|
|
This is my base xmobarrc. This is a full xmobar config with placeholders for the colors (i.e. =colorFgNormal=, =colorBgNormal=, =color01Normal=, =color01Bright=, etc...). [[./startup.sh][startup.sh]] copies this into =xmobarrc= with my current base16 color scheme. This also depends on =Inconsolata= and =Symbols Nerd Font=.
|
|
#+BEGIN_SRC haskell :tangle xmobarrc.mustache
|
|
Config { font = "Inconsolata 16"
|
|
, additionalFonts = ["Symbols Nerd Font 14"]
|
|
, border = NoBorder
|
|
, bgColor = "#{{base00-hex}}"
|
|
, alpha = 200
|
|
, fgColor = "#{{base05-hex}}"
|
|
, position = TopSize C 100 28
|
|
, textOffset = -1
|
|
, iconOffset = -1
|
|
, lowerOnStart = True
|
|
, pickBroadest = False
|
|
, persistent = False
|
|
, hideOnStart = False
|
|
, iconRoot = "."
|
|
, allDesktops = True
|
|
, overrideRedirect = True
|
|
, commands = [
|
|
Run XMonadLog
|
|
, Run Date "<fc=#{{base09-hex}}> <fn=1>\xf073</fn> %a %-m/%-d/%y %-I:%M:%S%P</fc>" "date" 10
|
|
, Run BatteryP ["BAT0"]
|
|
["-t", "<acstatus>",
|
|
"-L", "10", "-H", "80", "-p", "3", "--",
|
|
"-O","<fc=#{{base05-hex}}><fn=1>\xf313</fn></fc> <fc=#{{base0B-hex}}> <fn=1>\xf17e3</fn> <left>% </fc>",
|
|
"-i","<fc=#{{base05-hex}}><fn=1>\xf313</fn></fc> <fc=#{{base0B-hex}}> <fn=1>\xf17e7</fn> <left>% </fc>",
|
|
"-o","<fc=#{{base05-hex}}><fn=1>\xf313</fn></fc> <fc=#{{base08-hex}}> <fn=1>\xf17e4</fn> <left>% </fc>",
|
|
"-L", "-15", "-H", "-5",
|
|
"-l", "#{{base08-hex}}", "-m", "#{{base05-hex}}", "-h", "#{{base0B-hex}}"] 10
|
|
, Run Brightness
|
|
[ "-t", "<fc=#{{base0A-hex}}><fn=1>\xf0eb</fn> <percent>% </fc>", "--",
|
|
"-D", "amdgpu_bl1"
|
|
] 2
|
|
, Run Volume "default" "Master"
|
|
[ "-t", "<status>", "--"
|
|
, "--on", "<fc=#{{base0D-hex}}> <fn=1>\xf028</fn> <volume>% </fc>"
|
|
, "--onc", "#{{base0D-hex}}"
|
|
, "--off", "<fc=#{{base0F-hex}}> <fn=1>\xf026</fn> Mute </fc>"
|
|
, "--offc", "#{{base0F-hex}}"
|
|
] 1
|
|
, Run DynNetwork
|
|
[ "-t", "<fc=#{{base0D-hex}}><fn=1>\xf0200</fn> <dev></fc>"] 1
|
|
, Run Com "cat"
|
|
[ "/home/emmet/.st-status"] "syncthing" 10
|
|
, Run Com "echo"
|
|
[ "<fn=1>\xea77</fn> "] "syncthingsymbol" 0
|
|
, Run Com "echo"
|
|
[ "<fn=1>\xeb5c</fn> "] "artsymbol" 0
|
|
, Run Com "cat"
|
|
[ "/home/emmet/.currenttheme"] "currenttheme" 0
|
|
, Run Memory [ "-t", "<fc=#{{base08-hex}}><fn=1>\xf035b</fn> <usedratio>% (<used> GB)</fc>", "-d", "1", "--", "--scale", "1024"] 20
|
|
]
|
|
, sepChar = "%"
|
|
, alignSep = "}{"
|
|
, template = " %battery% %bright%<action=`xdotool key Super_L+y`>%default:Master%</action> %memory% %artsymbol%%currenttheme%}%XMonadLog%{<action=`librewolf localhost:8384`>%syncthing%</action> <action='networkmanager_dmenu'>%dynnetwork%</action> <action=`xdotool key Super_L+c`>%date%</action> "
|
|
}
|
|
}
|
|
|
|
#+END_SRC
|
|
|
|
#+BEGIN_SRC shell :tangle xmobar-st-check.sh.mustache
|
|
#!/bin/sh
|
|
while true
|
|
do
|
|
curl localhost:8384 -m 1 &> /dev/null || echo '<fc=#{{base08-hex}}>❄ st off</fc>' > ~/.st-status;
|
|
curl localhost:8384 -m 1 &> /dev/null && echo '<fc=#{{base0E-hex}}>↺ st on</fc>' > ~/.st-status;
|
|
sleep 5;
|
|
done
|
|
#+END_SRC
|
|
|
|
* Nix Integration
|
|
In order to have Nix put my xmonad/xmobar configuration in the proper places, I have [[./xmonad.nix][xmonad.nix]], which I source in the =imports= block of my [[../../home.nix][home.nix]].
|
|
#+BEGIN_SRC nix :tangle xmonad.nix
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
{
|
|
|
|
imports = [ ../picom/picom.nix
|
|
../../lang/haskell/haskell.nix
|
|
../../app/terminal/alacritty.nix
|
|
../../app/terminal/kitty.nix
|
|
( import ../../app/dmenu-scripts/networkmanager-dmenu.nix {dmenu_command = "rofi -show dmenu"; inherit config lib pkgs;})
|
|
];
|
|
|
|
home.packages = with pkgs; [
|
|
xmobar
|
|
networkmanagerapplet
|
|
dunst
|
|
pamixer
|
|
autorandr
|
|
alacritty
|
|
kitty
|
|
dmenu
|
|
rofi
|
|
keepmenu
|
|
networkmanager_dmenu
|
|
pavucontrol
|
|
feh
|
|
flameshot
|
|
alttab
|
|
xdotool
|
|
xclip
|
|
ddcutil
|
|
sct
|
|
libnotify
|
|
xorg.xkill
|
|
killall
|
|
bottom
|
|
brightnessctl
|
|
xorg.xcursorthemes
|
|
xorg.xev
|
|
xdg-utils
|
|
xdg-desktop-portal
|
|
xdg-desktop-portal-gtk
|
|
];
|
|
|
|
home.file.".config/xmonad/xmonad.hs".source = ./xmonad.hs;
|
|
home.file.".config/xmonad/startup.sh".source = ./startup.sh;
|
|
|
|
home.file.".config/xmonad/lib/Colors/Stylix.hs".source = config.lib.stylix.colors {
|
|
template = builtins.readFile ./lib/Colors/Stylix.hs.mustache;
|
|
extension = ".hs";
|
|
};
|
|
|
|
home.file.".config/xmobar/xmobarrc".source = config.lib.stylix.colors {
|
|
template = builtins.readFile ./xmobarrc.mustache;
|
|
extension = "";
|
|
};
|
|
|
|
|
|
home.file.".config/xmobar/xmobar-st-check.sh" = {
|
|
source = config.lib.stylix.colors {
|
|
template = builtins.readFile ./xmobar-st-check.sh.mustache;
|
|
extension = ".sh";
|
|
};
|
|
executable = true;
|
|
};
|
|
|
|
services.autorandr.enable = true;
|
|
programs.autorandr.enable = true;
|
|
programs.autorandr.profiles = {
|
|
"default" = {
|
|
fingerprint = {
|
|
eDP1 = "00ffffffffffff0051b8601500000000171e0104a522137807ee91a3544c99260f5054000000010101010101010101010101010101011434805070381f402b20750458c210000018000000fd0e302d505043010a20202020202000000010000a202020202020202020202020000000fc00544c3135365644585030310a2001d67013790000030114630401847f074f002a001f0037041e00160004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000df90";
|
|
};
|
|
config = {
|
|
eDP-1 = {
|
|
enable = true;
|
|
primary = true;
|
|
position = "0x0";
|
|
mode = "1920x1080";
|
|
};
|
|
};
|
|
hooks.postswitch = "xmonad --restart; ~/.fehbg-stylix;";
|
|
};
|
|
"dock" = {
|
|
fingerprint = {
|
|
eDP1 = "00ffffffffffff0051b8601500000000171e0104a522137807ee91a3544c99260f5054000000010101010101010101010101010101011434805070381f402b20750458c210000018000000fd0e302d505043010a20202020202000000010000a202020202020202020202020000000fc00544c3135365644585030310a2001d67013790000030114630401847f074f002a001f0037041e00160004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000df90";
|
|
HDMI-1 = "00ffffffffffff0010ac48f04c4a56470619010380342078ea1df5ae4f35b3250d5054a54b008180a940d100714f0101010101010101283c80a070b023403020360006442100001a000000ff00595947434e35323247564a4c0a000000fc0044454c4c2055323431330a2020000000fd00384c1e5111000a2020202020200163020325f15090050403020716011f1213142015110623091f0767030c001000382d83010000023a801871382d40582c450006442100001e011d8018711c1620582c250006442100009e011d007251d01e206e28550006442100001e8c0ad08a20e02d10103e960006442100001800000000000000000000000000000000000016";
|
|
DP-1-1 = "00ffffffffffff0010ac2ca0533836310e12010380342078eab325ac5130b426105054a54b008180a940714f01010101010101010101283c80a070b023403020360007442100001a000000ff004a55343336383356313638530a000000fc0044454c4c20323430385746500a000000fd00384c1e5311000a202020202020012002031bf14890050403020716012309070765030c00100083010000023a801871382d40582c450007442100001e011d8018711c1620582c250007442100009e011d007251d01e206e28550007442100001e8c0ad08a20e02d10103e96000744210000180000000000000000000000000000000000000000000000000000000047";
|
|
};
|
|
config = {
|
|
eDP-1 = {
|
|
enable = true;
|
|
primary = true;
|
|
position = "1000x1200";
|
|
mode = "1920x1080";
|
|
};
|
|
HDMI-1 = {
|
|
enable = true;
|
|
position = "1920x0";
|
|
mode = "1920x1200";
|
|
};
|
|
DP-1-1 = {
|
|
enable = true;
|
|
position = "0x0";
|
|
mode = "1920x1200";
|
|
};
|
|
};
|
|
hooks.postswitch = "xmonad --restart; ~/.fehbg-stylix;";
|
|
};
|
|
};
|
|
}
|
|
#+END_SRC
|