-- -- Xmonad config for Solomon Laing -- -- Base import XMonad import System.IO (hPutStrLn) import System.Exit (ExitCode(ExitSuccess), exitWith ) import qualified XMonad.StackSet as W -- Actions import XMonad.Actions.CopyWindow (kill1) import XMonad.Actions.CycleWS (moveTo, shiftTo, WSType(..), nextScreen, prevScreen) import XMonad.Actions.GridSelect import XMonad.Actions.MouseResize import XMonad.Actions.Submap import XMonad.Actions.Promote import XMonad.Actions.RotSlaves (rotSlavesDown, rotAllDown) import qualified XMonad.Actions.TreeSelect as TS import XMonad.Actions.WindowGo (runOrRaise) import XMonad.Actions.WithAll (sinkAll, killAll) import qualified XMonad.Actions.Search as S -- Data 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 -- Hooks import XMonad.Hooks.DynamicLog (dynamicLogWithPP, wrap, xmobarPP, xmobarColor, shorten, PP(..)) import XMonad.Hooks.FadeInactive import XMonad.Hooks.ManageDocks (docks, avoidStruts, docksEventHook, manageDocks, ToggleStruts(..)) import XMonad.Hooks.ManageHelpers (isFullscreen, doFullFloat) import XMonad.Hooks.EwmhDesktops (ewmh, fullscreenEventHook) import XMonad.Hooks.ServerMode import XMonad.Hooks.SetWMName import XMonad.Hooks.WorkspaceHistory -- Layouts import XMonad.Layout.GridVariants (Grid(Grid)) import XMonad.Layout.SimplestFloat import XMonad.Layout.Spiral import XMonad.Layout.ResizableTile import XMonad.Layout.Tabbed import XMonad.Layout.ThreeColumns -- Layouts modifiers --import XMonad.Layout.Fullscreen import XMonad.Layout.LayoutModifier import XMonad.Layout.LimitWindows (limitWindows, increaseLimit, decreaseLimit) import XMonad.Layout.Magnifier import XMonad.Layout.MultiToggle (mkToggle, single, EOT(EOT), (??)) import XMonad.Layout.MultiToggle.Instances (StdTransformers(NBFULL, MIRROR, NOBORDERS)) import XMonad.Layout.NoBorders import XMonad.Layout.Renamed import XMonad.Layout.ShowWName import XMonad.Layout.Simplest import XMonad.Layout.Spacing import XMonad.Layout.SubLayouts import XMonad.Layout.WindowNavigation import XMonad.Layout.WindowArranger (windowArrange, WindowArrangerMsg(..)) import qualified XMonad.Layout.ToggleLayouts as T (toggleLayouts, ToggleLayout(Toggle)) import qualified XMonad.Layout.MultiToggle as MT (Toggle(..)) -- Utilities import XMonad.Util.EZConfig (additionalKeysP) import XMonad.Util.Run (runProcessWithInput, safeSpawn, spawnPipe) import XMonad.Util.SpawnOnce --THEME -- #dfdfef (120,120,120) -- #9da5ae (157,165,174) -- #6b788b (107,120,139) -- #5c6776 (92,103,118) -- #45526d (69,82,109) -- #121e32 (18,30,49) -- The preferred terminal program, which is used in a binding below and by -- certain contrib modules. myTerminal :: String myTerminal = "alacritty" myFileManager :: String myFileManager = "thunar" -- The font to be used myFont :: String myFont = "xft:Fira Code:antialias=true:hinting=true" -- Whether focus follows the mouse pointer. myFocusFollowsMouse :: Bool myFocusFollowsMouse = True -- Whether clicking on a window to focus also passes the click to the window myClickJustFocuses :: Bool myClickJustFocuses = False -- Width of the window border in pixels. myBorderWidth :: Dimension myBorderWidth = 3 -- Border colors for unfocused and focused windows, respectively. myNormalBorderColor :: String myNormalBorderColor = "#121e32" myFocusedBorderColor :: String myFocusedBorderColor = "#6b788b" -- modMask lets you specify which modkey you want to use. The default -- is mod1Mask ("left alt"). You may also consider using mod3Mask -- ("right alt"), which does not conflict with emacs keybindings. The -- "windows key" is usually mod4Mask. myModMask :: KeyMask myModMask = mod4Mask -- The default number of workspaces (virtual screens) and their names. -- By default we use numeric strings, but any string may be used as a -- workspace name. The number of workspaces is determined by the length -- of this list. -- -- A tagging example: -- -- > workspaces = ["web", "irc", "code" ] ++ map show [4..9] xmobarEscape :: String -> String xmobarEscape = concatMap doubleLts where doubleLts '<' = "<<" doubleLts x = [x] myWorkspaces :: [String] -- myWorkspaces = [" 1 ", " 2 ", " 3 ", " 4 ", " 5 ", " 6 ", " 7 ", " 8 ", " 9 "] myWorkspaces = ["web", "game", "dev", "doc", "mus", "vid", "sys", "chat", "virt"] myWorkspaceIndices = M.fromList $ zipWith (,) myWorkspaces [1..] -- (,) == \x y -> (x,y) clickable ws = ""++ws++"" where i = fromJust $ M.lookup ws myWorkspaceIndices ------------------------------------------------------------------------ -- Key bindings. Add, modify or remove key bindings here. -- These are general keybindings custom script bindings are not included. myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList $ [ -- launch a terminal ((modm .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf) -- launch rofi , ((modm, xK_o ), spawn "rofi -show run") -- launch dmenu , ((modm, xK_a ), spawn "dmenu_run -bw 3 -c -l 15 -h 26") -- launch rofi ssh , ((modm .|. shiftMask, xK_o ), spawn "rofi -show ssh") -- launch my file manager , ((modm, xK_l ), spawn myFileManager) -- close focused window , ((modm .|. shiftMask, xK_j ), kill) -- 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_b ), refresh) -- Move focus to the next window , ((modm, xK_Tab ), windows W.focusDown) -- Move focus to the next window , ((modm .|. shiftMask, xK_Tab ), windows W.focusUp) -- Move focus to the next window , ((modm, xK_h ), windows W.focusDown) -- Move focus to the previous window , ((modm, xK_t ), windows W.focusUp ) -- Move focus to the master window , ((modm, xK_m ), windows W.focusMaster ) -- Swap the focused window and the master window , ((modm, xK_Return), windows W.swapMaster) -- Swap the focused window with the next window , ((modm .|. shiftMask, xK_Down ), windows W.swapDown ) -- Swap the focused window with the previous window , ((modm .|. shiftMask, xK_Up ), windows W.swapUp ) -- Shrink the master area , ((modm, xK_Left ), sendMessage Shrink) -- Expand the master area , ((modm, xK_Right ), sendMessage Expand) -- Push window back into tiling , ((modm, xK_y ), withFocused $ windows . W.sink) -- Increment the number of windows in the master area , ((modm, xK_w ), sendMessage (IncMasterN 1)) -- Deincrement the number of windows in the master area , ((modm, xK_v ), sendMessage (IncMasterN (-1))) -- Toggle the status bar gap -- Use this binding with avoidStruts from Hooks.ManageDocks. -- See also the statusBar function from Hooks.DynamicLog. -- , ((modm, xK_b ), sendMessage ToggleStruts) -- Quit xmonad , ((modm .|. shiftMask, xK_apostrophe ), io (exitWith ExitSuccess)) -- Restart xmonad , ((modm, xK_apostrophe ), spawn "xmonad --recompile; xmonad --restart") -- Run xmessage with a summary of the default keybindings (useful for beginners) , ((modm .|. shiftMask, xK_z ), spawn ("echo \"" ++ help ++ "\" | xmessage -file -")) ] ++ -- -- these are my general custom bindings and scripts -- [ -- prompt computer shutdown ((modm .|. shiftMask, xK_s ), spawn "/home/solomon/.local/bin/prompt \"Are you sure you want to Shutdown?\" \"shutdown now\"") -- prompt computer reboot , ((modm .|. shiftMask, xK_r ), spawn "/home/solomon/.local/bin/prompt \"Are you sure you want to Restart?\" \"reboot\"") -- prompt computer lock , ((modm, xK_Escape), spawn "/home/solomon/.local/bin/prompt \"Are you sure you want to lock?\" \"slock\" 1") -- unlock bitwarden cli and store session key , ((modm .|. shiftMask, xK_t ), spawn "/home/solomon/.local/bin/bw-unlock") -- search for password using bitwarden cli through dmenu , ((modm, xK_t ), spawn "/home/solomon/.local/bin/passwords") -- launch searcher , ((modm, xK_s ), spawn "/home/solomon/.local/bin/dmenusearch") , ((modm, xK_s), submap . M.fromList $ [ -- just open dmenusearch ((0, xK_a), spawn "/home/solomon/.local/bin/dmenusearch") -- open dmenusearch with duckduckgo preselected , ((0, xK_d), spawn "/home/solomon/.local/bin/dmenusearch duckduckgo") ]) -- launch mounter , ((modm, xK_c ), spawn "/home/solomon/.local/bin/dmenumount") -- launch unmounter , ((modm .|. shiftMask, xK_c ), spawn "/home/solomon/.local/bin/dmendduumount") ] ++ -- -- music controlls as I figure them out --por [ -- decrease volume with mod+f11 ((modm, xK_F11), spawn "/home/solomon/.local/bin/dec-sink-volume") -- increase volume with mod+f12 , ((modm, xK_F12), spawn "/home/solomon/.local/bin/inc-sink-volume") -- toggle mute with mod+f10 , ((modm, xK_F10), spawn "/home/solomon/.local/bin/toggle-sink-mute") -- decrease volume with mod+f11 , ((modm .|. shiftMask, xK_F11), spawn "/home/solomon/.local/bin/dec-source-volume") -- increase volume with mod+f12 , ((modm .|. shiftMask, xK_F12), spawn "/home/solomon/.local/bin/inc-source-volume") -- toggle mute with mod+f10 , ((modm .|. shiftMask, xK_F10), spawn "/home/solomon/.local/bin/toggle-source-mute") -- set default sink for pactl to allow above scripts to run , ((modm, xK_F7), spawn "/home/solomon/.local/bin/set-default-sink") -- set default source for pactl , ((modm .|. shiftMask, xK_F7), spawn "/home/solomon/.local/bin/set-default-source") ] ++ -- -- hardware controls, currently just backlight -- [ -- increase backlight by 10 with mod+f9 ((modm, xK_F9), spawn "backlight_control +5") -- decrese backlight by 10 with mod+f8x , ((modm, xK_F8), spawn "backlight_control -5") ] ++ -- -- 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)]] ++ -- -- mod-{w,e,r}, Switch to physical/Xinerama screens 1, 2, or 3 -- mod-shift-{w,e,r}, Move client to screen 1, 2, or 3 -- [((m .|. modm, key), screenWorkspace sc >>= flip whenJust (windows . f)) | (key, sc) <- zip [xK_comma, xK_period, xK_p] [0..] , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]] -- 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-button2, Raise the window to the top of the stack , ((modm, button2), (\w -> focus 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) ] ------------------------------------------------------------------------ -- Layouts: --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 True (Border i i i i) True (Border i i i i) True -- 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"] $ limitWindows 12 $ mySpacing 8 $ ResizableTall 1 (3/100) (1/2) [] magnify = renamed [Replace "magnify"] $ magnifier $ limitWindows 12 $ mySpacing 8 $ ResizableTall 1 (3/100) (1/2) [] monocle = renamed [Replace "monocle"] $ limitWindows 20 Full floats = renamed [Replace "floats"] $ limitWindows 20 simplestFloat grid = renamed [Replace "grid"] $ limitWindows 12 $ mySpacing 8 $ mkToggle (single MIRROR) $ Grid (16/10) spirals = renamed [Replace "spirals"] $ mySpacing 8 $ spiral (6/7) threeCol = renamed [Replace "threeCol"] $ limitWindows 7 $ ThreeCol 1 (3/100) (1/2) threeRow = renamed [Replace "threeRow"] $ limitWindows 7 -- Mirror takes a layout and rotates it by 90 degrees. -- So we are applying Mirror to the ThreeCol layout. $ Mirror $ ThreeCol 1 (3/100) (1/2) 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 -- setting colors for tabs layout and tabs sublayout. myTabTheme = def { fontName = myFont ++ ":size=12" , activeColor = "#6b788b" , inactiveColor = "#121e32" , activeBorderColor = "#6b788b" , inactiveBorderColor = "#121e32" , activeTextColor = "#121e32" , inactiveTextColor = "#dfdfef" } -- Theme for showWName which prints current workspace when you change workspaces. myShowWNameTheme :: SWNConfig myShowWNameTheme = def { swn_font = myFont ++ ":size=32" , swn_fade = 1.0 , swn_bgcolor = "#121e32" , swn_color = "#dfdfef" } -- The layout hook myLayout = avoidStruts $ mouseResize $ windowArrange $ T.toggleLayouts floats $ mkToggle (NBFULL ?? NOBORDERS ?? EOT) myDefaultLayout where -- I've commented out the layouts I don't use. myDefaultLayout = spirals ||| grid ||| noBorders monocle -- ||| tall ||| noBorders tabs -- ||| floats -- ||| magnify -- ||| threeCol -- ||| threeRow ------------------------------------------------------------------------ -- Window rules: -- Execute arbitrary actions and WindowSet manipulations when managing -- a new window. You can use this to, for example, always float a -- particular program, or have a client always appear on a particular -- workspace. -- -- To find the property name associated with a program, use -- > xprop | grep WM_CLASS -- and click on the client you're interested in. -- -- To match on the WM_NAME, you can use 'title' in the same way that -- 'className' and 'resource' are used below. myManageHook = composeAll [ className =? "Gimp" --> doFloat , className =? "guake" --> doIgnore , className =? "barrier" --> doFloat , className =? "net-runelite-client-RuneLite" --> doFloat , className =? "net-runelite-launcher-Launcher" --> doIgnore , resource =? "desktop_window" --> doIgnore , (className =? "firefox" <&&> resource =? "Dialog")--> doFloat -- Float Firefox Dialog , resource =? "kdesktop" --> doIgnore , className =? "MusicBrainz Picard" --> doIgnore , className =? "Steam" --> doShift ( myWorkspaces !! (7-1) ) , className =? "discord" --> doShift ( myWorkspaces !! (8-1) ) , className =? "telegram-desktop" --> doShift ( myWorkspaces !! (8-1) ) , className =? "Pavucontrol" --> doShift ( myWorkspaces !! (5-1) )] ------------------------------------------------------------------------ -- Event handling -- * EwmhDesktops users should change this to ewmhDesktopsEventHook -- -- Defines a custom handler function for X Events. The function should -- return (All True) if the default handler is to be run afterwards. To -- combine event hooks use mappend or mconcat from Data.Monoid. myEventHook = mempty -- Status bars and logging -- Perform an arbitrary action on each internal state change or X event. -- See the 'XMonad.Hooks.DynamicLog' extension for examples. myLogHook :: X () myLogHook = fadeInactiveLogHook fadeAmount where fadeAmount = 1.0 ------------------------------------------------------------------------ -- Startup hook -- Perform an arbitrary action each time xmonad starts or is restarted -- with mod-q. Used by, e.g., XMonad.Layout.PerWorkspace to initialize -- per-workspace layout choices. -- -- By default, do nothing. myStartupHook = do -- Startup apps (tray) and settings spawnOnce "volumeicon &" spawnOnce "nm-applet &" spawnOnce "blueman-applet &" spawnOnce "kdeconnect-indicator &" spawnOnce "dunst &" -- notification daemon -- Startup Applications spawnOnce "guake &" spawnOnce "barrier &" spawnOnce "nextcloud &" spawnOnce "slack &" spawnOnce "todoist &" -- Start trayer last spawnOnce "trayer --edge top --align right --widthtype request --padding 6 --SetDockType true --SetPartialStrut true --expand true --monitor 1 --transparent true --alpha 0 --tint 0x121e32 --height 24 &" ------------------------------------------------------------------------ -- Now run xmonad with all the defaults we set up. -- Run xmonad with the settings you specify. No need to modify this. main :: IO () main = do xmproc <- spawnPipe "xmobar -x 0 /home/solomon/.config/xmobar/xmobarrc.hs" -- xmproc <- spawnPipe "xmobar -x 0 /home/solomon/.config/xmobar/xmobarrc0" -- xmproc <- spawnPipe "xmobar -x 1 /home/solomon/.config/xmobar/xmobarrc1" -- xmproc <- spawnPipe "xmobar -x 2 /home/solomon/.config/xmobar/xmobarrc2" -- xmonad =<< statusBar myBar myPP toggleStrutsKey defaults xmonad $ ewmh $ docks def -- defaults = 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 = showWName' myShowWNameTheme $ myLayout, manageHook = ( isFullscreen --> doFullFloat ) <+> myManageHook <+> manageDocks, handleEventHook = myEventHook <+> fullscreenEventHook, -- logHook = myLogHook, logHook = myLogHook <+> dynamicLogWithPP xmobarPP { ppOutput = \x -> hPutStrLn xmproc x , ppCurrent = xmobarColor "#a8de45" "" . wrap "[" "]" -- Current workspace in xmobar , ppVisible = xmobarColor "#88ae55" "" . clickable -- Visible but not current workspace , ppHidden = xmobarColor "#82AAFF" "" . wrap "*" "" . clickable -- Hidden workspaces in xmobar , ppHiddenNoWindows = xmobarColor "#9da5ae" "" . clickable -- Hidden workspaces (no windows) -- , ppTitle = xmobarColor "#b3afc2" "" . shorten 20 -- 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] , ppOrder = \(ws:l:t:ex) -> [ws,l] }, startupHook = myStartupHook } -- | Finally, a copy of the default bindings in simple textual tabular format. help :: String help = unlines ["The default modifier key is 'alt'. Default keybindings:", "", "-- launching and killing programs", "mod-Shift-Enter Launch terminal", "mod-a Launch run menu", "mod-Shift-a Launch ssh menu", "mod-o Launch dmenu", "mod-l Launch file manager", "mod-Shift-j Close/kill the focused window", "mod-Space Rotate through the available layout algorithms", "mod-Shift-Space Reset the layouts on the current workSpace to default", "mod-n Resize/refresh viewed windows to the correct size", "", "-- move focus up or down the window stack", "mod-Tab Move focus to the next window", "mod-Shift-Tab Move focus to the previous window", "mod-h Move focus to the next window", "mod-t Move focus to the previous window", "mod-m Move focus to the master window", "", "-- modifying the window order", "mod-Return Swap the focused window and the master window", "mod-Shift-h Swap the focused window with the next window", "mod-Shift-t Swap the focused window with the previous window", "", "-- resizing the master/slave ratio", "mod-d Shri sk the master area", "mod-n Expand the master area", "", "-- floating layer support", "mod-y Push window back into tiling; unfloat and re-tile it", "", "-- increase or decrease number of windows in the master area", "mod-w (mod-,) Increment the number of windows in the master area", "mod-vL (mod-.) Deincrement the number of windows in the master area", "", "-- quit, or restart", "mod-Shift-' Quit xmonad", "mod-' Restart xmonad", "mod-[1..9] Switch to workSpace N", "", "-- Workspaces & screens", "mod-Shift-[1..9] Move client to workspace N", "mod-{',','.','p'} Switch to physical/Xinerama screens 1, 2, or 3", "mod-Shift-{',','.','p'} Move client to screen 1, 2, or 3", "", "-- Mouse bindings: default actions bound to mouse events", "mod-button1 Set the window to floating mode and move by dragging", "mod-button2 Raise the window to the top of the stack", "mod-button3 Set the window to floating mode and resize by dragging"]