-- -- xmonad example config file. -- -- A template showing all available configuration hooks, -- and how to override the defaults in your own xmonad.hs conf file. -- -- Normally, you'd only override those defaults you care about. -- -- Imports for Polybar import qualified Codec.Binary.UTF8.String as UTF8 import qualified DBus as D import qualified DBus.Client as D import qualified Data.Map as M import Data.Monoid import System.Exit import XMonad import XMonad.Actions.CycleSelectedLayouts (cycleThroughLayouts) import XMonad.Actions.EasyMotion ( ChordKeys (..), EasyMotionConfig (..), selectWindow, ) import XMonad.Hooks.DynamicLog import XMonad.Hooks.EwmhDesktops import XMonad.Hooks.ManageDocks import XMonad.Hooks.ManageHelpers ( composeOne, doCenterFloat, isDialog, (-?>), ) import XMonad.Hooks.StatusBar import XMonad.Hooks.StatusBar.PP import XMonad.Layout.BoringWindows (boringWindows) import XMonad.Layout.Gaps (gaps) import XMonad.Layout.Grid import XMonad.Layout.LimitWindows (limitWindows) import XMonad.Layout.NoBorders (smartBorders) import XMonad.Layout.Spacing (spacing) import XMonad.Layout.ThreeColumns (ThreeCol (..)) import qualified XMonad.StackSet as W import XMonad.Util.EZConfig import XMonad.Util.Run -- The preferred terminal program, which is used in a binding below and by -- certain contrib modules. -- myTerminal = "alacritty" -- 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 -- Width of the window border in pixels. -- myBorderWidth = 2 -- 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 = mod1Mask -- Workspaces webWs = "web" finWs = "fin" sysWs = "sys" comWs = "com" devWs = ["dev", "dev2", "dev3"] myWorkspaces = [webWs] <> devWs <> [finWs, sysWs, comWs] -- Colors blue = "#2E9AFE" gray = "#7F7F7F" orange = "#ea4300" purple = "#9058c7" red = "#722222" -- Border colors for unfocused and focused windows, respectively. -- myNormalBorderColor = gray myFocusedBorderColor = blue main :: IO () main = mkDbusClient >>= main' main' :: D.Client -> IO () main' dbus = xmonad . docks . ewmhFullscreen . 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, handleEventHook = myEventHook, logHook = myPolybarLogHook dbus, startupHook = myStartupHook } ------------------------------------------------------------------------ -- Polybar settings (needs DBus client). -- mkDbusClient :: IO D.Client mkDbusClient = do dbus <- D.connectSession D.requestName dbus (D.busName_ "org.xmonad.log") opts return dbus where opts = [D.nameAllowReplacement, D.nameReplaceExisting, D.nameDoNotQueue] -- Emit a DBus signal on log updates dbusOutput :: D.Client -> String -> IO () dbusOutput dbus str = let opath = D.objectPath_ "/org/xmonad/Log" iname = D.interfaceName_ "org.xmonad.Log" mname = D.memberName_ "Update" signal = D.signal opath iname mname body = [D.toVariant $ UTF8.decodeString str] in D.emit dbus $ signal {D.signalBody = body} polybarHook :: D.Client -> PP polybarHook dbus = let wrapper c = wrap ("%{F" <> c <> "}") "%{F-}" in def { ppOutput = dbusOutput dbus, ppCurrent = wrapper blue, ppVisible = wrapper purple, ppUrgent = wrapper orange, ppHidden = wrapper gray, ppHiddenNoWindows = wrapper red, ppTitle = wrapper purple . shorten 90 } myPolybarLogHook dbus = myLogHook <+> dynamicLogWithPP (polybarHook dbus) ------------------------------------------------------------------------ -- Layouts: -- You can specify and transform your layouts by modifying these values. -- If you change layout bindings be sure to use 'mod-shift-space' after -- restarting (with 'mod-q') to reset your layout state to the new -- defaults, as xmonad preserves your old layout settings by default. -- -- The available layouts. Note that each layout is separated by |||, -- which denotes layout choice. -- myLayout = avoidStruts . smartBorders $ (Mirror tiled ||| tiled ||| column3 ||| full) where full = Full tiled = gapSpaced 5 $ Tall nmaster incRatio ratio column3 = gapSpaced 5 $ ThreeColMid nmaster incRatio ratio nmaster = 1 incRatio = (3 / 100) ratio = (1 / 2) gapSpaced g = spacing g . myGaps g myGaps gap = gaps [(U, gap), (D, gap), (L, gap), (R, gap)] ------------------------------------------------------------------------ -- 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 = return () ------------------------------------------------------------------------ -- 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 = return () ------------------------------------------------------------------------ -- 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 ------------------------------------------------------------------------ -- 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 = manageApps where isRole = stringProperty "WM_WINDOW_ROLE" isPopup = isRole =? "pop-up" manageApps = composeOne [ resource =? "desktop_window" -?> doIgnore, resource =? "kdesktop" -?> doIgnore, -- general isPopup -?> doCenterFloat, isDialog -?> doCenterFloat, -- apps className =? "Gimp" -?> doFloat, className =? "nheko" -?> doShift comWs, className =? "KotatogramDesktop" -?> doShift comWs, className =? "gnome-calculator" -?> doCenterFloat ] ------------------------------------------------------------------------ -- Key bindings. Add, modify or remove key bindings here. -- myKeys conf = mkKeymap conf $ -- launch a terminal [ ("M-S-", spawn $ XMonad.terminal conf), -- launch a 'flameshot' to screenshot ("M-S-s", safeSpawn "flameshot" ["gui"]), -- launch 'librewolf' browser ("M-S-b", spawn "librewolf"), -- launch 'dmenu_run' to choose applications ("M-p", spawn "dmenu_run"), -- close focused window ("M4-S-c", kill), -- Rotate through the available layout algorithms ("M-", cycleThroughLayouts ["Full", "Mirror Spacing Tall"]), ("M-", cycleThroughLayouts ["Spacing ThreeCol", "Spacing Tall", "Mirror Spacing Tall"]), -- Reset the layouts on the current workspace to default ("M-S-", setLayout $ XMonad.layoutHook conf), -- Resize viewed windows to the correct size ("M-n", refresh), -- Easy moution to focus windows ("M-s", selectWindow easyMotionConfig >>= (`whenJust` windows . W.focusWindow)), -- Move focus to the next window ("M-j", windows W.focusDown), -- Move focus to the previous window ("M-k", windows W.focusUp), -- Move focus to the master window ("M-m", windows W.focusMaster), -- Swap the focused window and the master window ("M-", windows W.swapMaster), -- Swap the focused window with the next window ("M-S-j", windows W.swapDown), -- Swap the focused window with the previous window ("M-S-k", windows W.swapUp), -- Shrink the master area ("M-h", sendMessage Shrink), -- Expand the master area ("M-l", sendMessage Expand), -- Push window back into tiling ("M-t", withFocused $ windows . W.sink), -- Increment the number of windows in the master area ("M-,", sendMessage $ IncMasterN 1), -- Deincrement the number of windows in the master area ("M-.", sendMessage $ IncMasterN (-1)), -- Toggle the status bar gap -- Use this binding with avoidStruts from Hooks.ManageDocks. -- See also the statusBar function from Hooks.DynamicLog. -- -- , ("M-b", sendMessage ToggleStruts) -- Lock screen ("M4-l", spawn "betterlockscreen --lock --display 1 -- -e"), -- Change volume ("", spawn "amixer -q sset Master toggle"), ("", spawn "amixer -q sset Master 5%+"), ("", spawn "amixer -q sset Master 5%-"), -- Keyboard apps ("", spawn "gnome-calculator"), -- Quit xmonad ("M4-S-q", io exitSuccess) ] ++ -- -- mod-[1..9], Switch to workspace N -- mod-shift-[1..9], Move client to workspace N -- [ ("M-" ++ m ++ show k, windows $ f i) | (i, k) <- zip (XMonad.workspaces conf) [1 .. 9], (f, m) <- [(W.greedyView, ""), (W.shift, "S-")] ] where easyMotionConfig = def { sKeys = AnyKeys [xK_a, xK_o, xK_e, xK_u, xK_h, xK_t, xK_n, xK_s] } ------------------------------------------------------------------------ -- 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) ]