xmonad is a tiling window manager written and configured in haskell
Though I do not know haskell, the build in configuration for xmonad on archcraft is good enough that with a few tweaks I am very happy about my config.
xMonad allows for easy binding of keys to spawning a process, and configuration of workspaces and such like that.
here is my config
-- Copyright (C) 2020-2023 Aditya Shakya <[email protected]>
--
-- Xmonad config for Archcraft
-- ## Modules ## -------------------------------------------------------------------
import XMonad
import XMonad.Util.SpawnOnce
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers
import XMonad.Layout.Fullscreen
import XMonad.Layout.NoBorders
import XMonad.Layout.Spacing
import XMonad.Layout.Gaps
import Graphics.X11.ExtraTypes.XF86
import System.Exit
import Control.Monad
import Data.Monoid
import Data.Maybe
import qualified XMonad.StackSet as W
import qualified Data.Map as M
-- ## Startup hook ## ---------------------------------------------------------------
myStartupHook = do
spawn "bash ~/.xmonad/scripts/xmonad_autostart"
-- ## Applications ## ---------------------------------------------------------------
-- Terminal
myTerminal = "~/.xmonad/scripts/xmonad_term"
-- Apps
file_manager = spawn "thunar"
text_editor = spawn "alacritty -e helix"
web_browser = spawn "firefox"
-- Rofi Menus
rofi_network_menu = spawn "~/.xmonad/scripts/network_menu"
rofi_asroot = spawn "~/.xmonad/scripts/rofi_asroot"
rofi_bluetooth = spawn "~/.xmonad/scripts/rofi_bluetooth"
rofi_launcher = spawn "~/.xmonad/scripts/rofi_launcher"
-- rofi_mpd = spawn "~/.xmonad/scripts/rofi_music"
rofi_powermenu = spawn "~/.xmonad/scripts/rofi_powermenu"
rofi_runner = spawn "~/.xmonad/scripts/rofi_runner"
-- rofi_screenshot = spawn "~/.xmonad/scripts/rofi_screenshot"
rofi_windows = spawn "~/.xmonad/scripts/rofi_windows"
-- ## Settings ## -------------------------------------------------------------------
-- focus follows the mouse pointer
myFocusFollowsMouse :: Bool
myFocusFollowsMouse = False
-- clicking on a window to focus
myClickJustFocuses :: Bool
myClickJustFocuses = False
-- Width of the window border in pixels
myBorderWidth = 1
-- Border colors for focused & unfocused windows
myFocusedBorderColor = "#ea73bc"
myNormalBorderColor = "#b48dee"
-- modMask : modkey you want to use
-- mod1Mask : left alt Key
-- mod4Mask : Windows or Super Key
myModMask = mod4Mask
-- Workspaces (ewmh)
myWorkspaces = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"]
-- ## Key Bindings ## -------------------------------------------------------------------
myKeys conf@(XConfig {XMonad.modMask = super}) = M.fromList $
-- launch terminal
[ ((super, xK_Return), spawn $ XMonad.terminal conf)
, ((super .|. shiftMask, xK_Return), spawn "~/.xmonad/scripts/xmonad_term --float")
, ((super .|. mod1Mask, xK_Return), spawn "~/.xmonad/scripts/xmonad_term --full")
-- launch applications
, ((super .|. shiftMask, xK_f), file_manager)
, ((super .|. shiftMask, xK_e), text_editor)
, ((super .|. shiftMask, xK_w), web_browser)
-- launch rofi menus
, ((mod1Mask, xK_F1), rofi_launcher)
, ((mod1Mask, xK_F2), rofi_runner)
, ((super, xK_b), rofi_bluetooth)
, ((super, xK_n), rofi_network_menu)
, ((super, xK_x), rofi_powermenu)
-- , ((super, xK_m), rofi_mpd)
, ((super, xK_s), spawn "flameshot gui")
, ((super, xK_t), spawn "playerctl play-pause")
, ((super, xK_r), rofi_asroot)
, ((super, xK_w), rofi_windows)
, ((super, xK_m), spawn "polybar-msg cmd toggle")
-- Audio keys
, ((0, xF86XK_AudioPlay), spawn "mpc toggle")
, ((0, xF86XK_AudioPrev), spawn "mpc prev")
, ((0, xF86XK_AudioNext), spawn "mpc next")
, ((0, xF86XK_AudioStop), spawn "mpc stop")
, ((0, xF86XK_AudioRaiseVolume), spawn "~/.xmonad/scripts/xmonad_volume --inc")
, ((0, xF86XK_AudioLowerVolume), spawn "~/.xmonad/scripts/xmonad_volume --dec")
, ((0, xF86XK_AudioMute), spawn "~/.xmonad/scripts/xmonad_volume --toggle")
, ((0, xF86XK_AudioMicMute), spawn "~/.xmonad/scripts/xmonad_volume --toggle-mic")
-- Brightness keys
, ((0, xF86XK_MonBrightnessUp), spawn "~/.xmonad/scripts/xmonad_brightness --inc")
, ((0, xF86XK_MonBrightnessDown), spawn "~/.xmonad/scripts/xmonad_brightness --dec")
-- Screenshot
, ((0, xK_Print), spawn $ "~/.xmonad/scripts/xmonad_screenshot --now")
, ((mod1Mask, xK_Print), spawn $ "~/.xmonad/scripts/xmonad_screenshot --in5")
, ((shiftMask, xK_Print), spawn $ "~/.xmonad/scripts/xmonad_screenshot --in10")
, ((controlMask, xK_Print), spawn $ "~/.xmonad/scripts/xmonad_screenshot --win")
, ((super, xK_Print), spawn $ "~/.xmonad/scripts/xmonad_screenshot --area")
-- Close focused window
, ((super, xK_c), kill)
, ((super, xK_Escape), spawn "xkill")
-- Lockscreen
, ((super .|. shiftMask, xK_z), spawn "xscreensaver-command -lock")
, ((mod1Mask .|. controlMask, xK_l), spawn "betterlockscreen --lock")
-- Misc
, ((super, xK_p), spawn "~/.xmonad/scripts/xmonad_colorpicker")
-- , ((controlMask, xK_t), spawn "/bin/sh -c /home/tommy/.xmonad/scripts/tbind")
-- Change gaps on the fly
, ((super .|. controlMask, xK_g), sendMessage $ ToggleGaps) -- toggle all gaps
, ((super .|. shiftMask, xK_g), sendMessage $ setGaps [(L,50), (R,50), (U,80), (D,50)]) -- reset the GapSpec
, ((super .|. controlMask, xK_t), sendMessage $ IncGap 10 L) -- increment the left-hand gap
, ((super .|. shiftMask, xK_t), sendMessage $ DecGap 10 L) -- decrement the left-hand gap
, ((super .|. controlMask, xK_y), sendMessage $ IncGap 10 U) -- increment the top gap
, ((super .|. shiftMask, xK_y), sendMessage $ DecGap 10 U) -- decrement the top gap
, ((super .|. controlMask, xK_u), sendMessage $ IncGap 10 D) -- increment the bottom gap
, ((super .|. shiftMask, xK_u), sendMessage $ DecGap 10 D) -- decrement the bottom gap
, ((super .|. controlMask, xK_i), sendMessage $ IncGap 10 R) -- increment the right-hand gap
, ((super .|. shiftMask, xK_i), sendMessage $ DecGap 10 R) -- decrement the right-hand gap
-- Window Manager Specific -----------------------------------------
-- Resize viewed windows to the correct size
, ((super .|. shiftMask, xK_r), refresh)
-- Move focus to the master window
, ((super .|. shiftMask, xK_m), windows W.focusMaster)
-- Swap the focused window and the master window
, ((super .|. shiftMask, xK_s), windows W.swapMaster)
-- Push window back into tiling
, ((super .|. shiftMask, xK_t), withFocused $ windows . W.sink)
-- Rotate through the available layout algorithms
, ((super, xK_space), sendMessage NextLayout)
-- Reset the layouts on the current workspace to default
, ((super .|. shiftMask, xK_space), setLayout $ XMonad.layoutHook conf)
-- Move focus to the next window
, ((super, xK_Tab), windows W.focusDown)
-- Move focus to the next window
, ((super, xK_j), windows W.focusDown)
, ((super, xK_Left), windows W.focusDown)
-- Move focus to the previous window
, ((super, xK_k), windows W.focusUp)
, ((super, xK_Right), windows W.focusUp)
-- Swap the focused window with the next window
, ((super .|. shiftMask, xK_j), windows W.swapDown)
, ((super .|. shiftMask, xK_Left), windows W.swapDown)
-- Swap the focused window with the previous window
, ((super .|. shiftMask, xK_k), windows W.swapUp)
, ((super .|. shiftMask, xK_Right), windows W.swapUp)
-- Shrink the master area
, ((super, xK_h), sendMessage Shrink)
, ((super .|. controlMask, xK_Left), sendMessage Shrink)
-- Expand the master area
, ((super, xK_l), sendMessage Expand)
, ((super .|. controlMask, xK_Right), sendMessage Expand)
-- Increment the number of windows in the master area
, ((super, xK_comma), sendMessage (IncMasterN 1))
-- Deincrement the number of windows in the master area
, ((super, xK_period), sendMessage (IncMasterN (-1)))
-- Restart xmonad
, ((super, xK_q), spawn "xmonad --recompile; xmonad --restart")
-- , ((controlMask, xK_t), spawn "xdotool key t")
]
++
-- Workspace Specific ---------------------------------------------------------------
-- mod-[1..9], Switch to workspace N
-- mod-shift-[1..9], Move client to workspace N
[((m .|. super, k), windows $ f i)
| (i, k) <- zip (XMonad.workspaces conf) [xK_1,xK_2,xK_3,xK_4,xK_5,xK_6,xK_7,xK_8,xK_9,xK_0]
, (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
++
-- mod-{y,u,i}, Switch to physical/Xinerama screens 1, 2, or 3
-- mod-shift-{y,u,i}, Move client to screen 1, 2, or 3
[((m .|. super, key), screenWorkspace sc >>= flip whenJust (windows . f))
| (key, sc) <- zip [xK_y, xK_u, xK_i] [0..]
, (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]
-- ## Mouse Bindings ## ------------------------------------------------------------------
myMouseBindings (XConfig {XMonad.modMask = super}) = M.fromList $
-- mod-button1, Set the window to floating mode and move by dragging
[ ((super, button1), (\w -> focus w >> mouseMoveWindow w
>> windows W.shiftMaster))
-- mod-button2, Raise the window to the top of the stack
, ((super, button2), (\w -> focus w >> windows W.shiftMaster))
-- mod-button3, Set the window to floating mode and resize by dragging
, ((super, button3), (\w -> focus w >> mouseResizeWindow w
>> windows W.shiftMaster))
]
-- ## Layouts ## -------------------------------------------------------------------------
myLayout = avoidStruts(tiled ||| Mirror tiled ||| Full)
where
-- default tiling algorithm partitions the screen into two panes
tiled = Tall nmaster delta ratio
-- The default number of windows in the master pane
nmaster = 1
-- Default proportion of screen occupied by master pane
ratio = 1/2
-- Percent of screen to increment by when resizing panes
delta = 3/100
-- ## Window rules ## --------------------------------------------------------------------
myManageHook = composeAll . concat $
[ [isDialog --> doCenterFloat]
, [className =? c --> doCenterFloat | c <- myCFloats]
, [title =? t --> doCenterFloat | t <- myTFloats]
, [resource =? r --> doFloat | r <- myRFloats]
, [resource =? i --> doIgnore | i <- myIgnores]
]
where
myCFloats = ["alacritty-float", "Music", "MPlayer", "mpv",
"Gimp", "feh", "Viewnior", "Gpicview",
"Kvantum Manager", "qt5ct", "VirtualBox Manager", "qemu", "Qemu-system-x86_64",
"Lxappearance", "Nitrogen", "Arandr", "Pavucontrol", "Xfce4-power-manager-settings", "Nm-connection-editor"]
myTFloats = ["Downloads", "Save As...", "About : Aditya Shakya", "Getting Started"]
myRFloats = []
myIgnores = ["desktop_window"]
-- ## Event handling ## -------------------------------------------------------------------
--myEventHook = ewmhDesktopsEventHook
-- ## Logging ## --------------------------------------------------------------------------
myLogHook = return ()
-- ## Main Function ## --------------------------------------------------------------------
-- Run xmonad with all the configs we set up.
main = xmonad $ fullscreenSupport $ docks $ ewmh defaults
defaults = def {
-- configs
terminal = myTerminal,
focusFollowsMouse = myFocusFollowsMouse,
clickJustFocuses = myClickJustFocuses,
borderWidth = myBorderWidth,
modMask = myModMask,
workspaces = myWorkspaces,
normalBorderColor = myNormalBorderColor,
focusedBorderColor = myFocusedBorderColor,
-- key bindings
keys = myKeys,
mouseBindings = myMouseBindings,
-- hooks, layouts
manageHook = myManageHook,
layoutHook = gaps [(L,0), (R,0), (U,0), (D,0)] $ spacingRaw False (Border 10 0 10 0) True (Border 0 10 0 10) True $ myLayout,
--handleEventHook = myEventHook,
logHook = myLogHook,
startupHook = myStartupHook
}