dots-of-war/files/.xmonad/xmonad.hs

256 lines
9 KiB
Haskell
Raw Normal View History

2020-03-19 11:03:08 +00:00
{-# Language ScopedTypeVariables #-}
2020-03-19 13:14:18 +00:00
-- Imports -------------------------------------------------------- {{{
2020-03-19 11:03:08 +00:00
import qualified Data.Map as M
2020-03-20 19:00:15 +00:00
import Data.List (isSuffixOf)
2020-03-19 14:14:16 +00:00
import qualified Data.Maybe as Maybe
import qualified System.IO as SysIO
2020-03-19 11:03:08 +00:00
import Text.Read (readMaybe)
import Data.Char (isDigit)
2020-03-20 15:40:53 +00:00
import System.Exit (exitWith, ExitCode(ExitSuccess))
2020-03-19 11:03:08 +00:00
import qualified Data.Monoid
import qualified DBus as D
import qualified DBus.Client as D
import qualified Codec.Binary.UTF8.String as UTF8
import XMonad hiding ((|||))
2020-03-19 14:14:16 +00:00
import qualified XMonad.Util.Dmenu as Dmenu
2020-03-19 11:03:08 +00:00
import qualified XMonad.StackSet as W
2020-03-19 14:14:16 +00:00
import XMonad.Actions.CopyWindow
import XMonad.Actions.Submap
import XMonad.Config.Desktop
2020-03-20 15:40:53 +00:00
import XMonad.Hooks.EwmhDesktops (ewmh)
2020-03-19 11:03:08 +00:00
import XMonad.Hooks.DynamicLog
2020-03-20 19:00:15 +00:00
import XMonad.Hooks.ManageHelpers
2020-03-19 14:14:16 +00:00
import XMonad.Hooks.DynamicProperty
2020-03-19 11:03:08 +00:00
import XMonad.Hooks.FadeInactive
2020-03-19 14:14:16 +00:00
import XMonad.Hooks.ManageDocks
2020-03-19 11:03:08 +00:00
import XMonad.Hooks.SetWMName (setWMName)
import XMonad.Layout.Gaps
2020-03-20 15:40:53 +00:00
import XMonad.Layout.LayoutHints
import XMonad.Layout.Accordion
2020-03-19 14:14:16 +00:00
import XMonad.Layout.Grid -- for additional grid layout
import XMonad.Layout.LayoutCombinators ((|||))
import XMonad.Layout.MouseResizableTile -- for mouse control
import XMonad.Layout.NoBorders -- for fullscreen without borders
2020-03-19 11:03:08 +00:00
import XMonad.Layout.Renamed
2020-03-19 14:14:16 +00:00
import XMonad.Layout.ResizableTile -- for resizeable tall layout
2020-03-19 11:03:08 +00:00
import XMonad.Layout.Spacing
import XMonad.Layout.Spiral
import XMonad.Layout.ThreeColumns -- for three column layout
2020-03-19 14:14:16 +00:00
import XMonad.Layout.ToggleLayouts
import XMonad.ManageHook
2020-03-20 15:40:53 +00:00
import XMonad.Util.EZConfig (additionalKeys, additionalKeysP, removeKeysP)
2020-03-19 14:14:16 +00:00
import XMonad.Util.NamedScratchpad
2020-03-20 15:40:53 +00:00
import XMonad.Util.Run
2020-03-19 11:03:08 +00:00
import XMonad.Util.SpawnOnce (spawnOnce)
2020-03-19 14:14:16 +00:00
import qualified XMonad.Layout.LayoutCombinators as LayoutCombinators
2020-03-19 11:03:08 +00:00
-- }}}
-- Values -------------------- {{{
myModMask = mod4Mask
myLauncher = "rofi -show run"
2020-03-22 18:05:29 +00:00
--myTerminal = "termite"
myTerminal = "kitty --single-instance"
2020-03-19 13:14:18 +00:00
myBrowser = "google-chrome-stable"
2020-03-19 11:03:08 +00:00
--yBar = "xmobar"
--myXmobarPP= xmobarPP { ppCurrent = xmobarColor "#429942" "" . wrap "<" ">" }
scratchpads :: [NamedScratchpad]
scratchpads =
[ NS "terminal" (myTerminal ++ " --class scratchpad_term") (className =? "scratchpad_term")
(customFloating $ W.RationalRect 0 0.7 1 0.3)
2020-03-19 13:14:18 +00:00
, NS "ghci" (myTerminal ++ " -e \"stack exec -- ghci\" --class scratchpad_ghci") (className =? "scratchpad_ghci")
2020-03-19 11:03:08 +00:00
(customFloating $ W.RationalRect 0 0.7 1 0.3)
2020-03-20 19:00:15 +00:00
, NS "whatsapp" ("gtk-launch chrome-hnpfjngllnobngcgfapefoaidbinmjnm-Default.desktop") (("WhatsApp" `isSuffixOf`) <$> title) defaultFloating
2020-03-19 11:03:08 +00:00
]
2020-03-20 15:40:53 +00:00
{-| adds the scripts-directory path to the filename of a script |-}
scriptFile :: String -> String
scriptFile script = "/home/leon/scripts/" ++ script
2020-03-19 11:03:08 +00:00
-- Colors ------ {{{
fg = "#ebdbb2"
bg = "#282828"
gray = "#a89984"
bg1 = "#3c3836"
bg2 = "#504945"
bg3 = "#665c54"
bg4 = "#7c6f64"
green = "#b8bb26"
darkgreen = "#98971a"
red = "#fb4934"
darkred = "#cc241d"
yellow = "#fabd2f"
blue = "#83a598"
purple = "#d3869b"
aqua = "#8ec07c"
-- }}}
-- }}}
-- Layout ---------------------------------------- {{{
2020-03-20 15:40:53 +00:00
myLayout = smartBorders $ withGaps $ toggleLayouts Full $ withSpacing $ layoutHints
2020-03-19 11:03:08 +00:00
( ResizableTall 1 (3/100) (1/2) []
||| Mirror (ResizableTall 1 (3/100) (3/4) [])
||| spiral (6/7) -- Grid
||| ThreeColMid 1 (3/100) (1/2)
)
-- mouseResizableTile ||| Mirror mouseResizableTile
where
-- add spacing between windows
withSpacing = spacingRaw True (Border 0 0 0 0) True (Border 10 10 10 10) True
2020-03-20 15:40:53 +00:00
withGaps = gaps' [((L, 10), True),((U, 10), True), ((D, 10), True), ((R, 10), True )]
2020-03-19 11:03:08 +00:00
-- }}}
-- Loghook -------------------------------------- {{{
myLogHook :: X ()
myLogHook = do
fadeInactiveLogHook 0.95 -- opacity of unfocused windows
--(W.StackSet _ layout _ _ ) <- gets windowset
-- }}}
-- Startuphook ----------------------------- {{{
myStartupHook = do
spawnOnce "picom --config ~/.config/picom.conf --no-fading-openclose"
spawnOnce "pasystray"
spawn "/home/leon/.config/polybar/launch.sh"
2020-03-20 19:00:15 +00:00
setWMName "LG3D" -- Java stuff hack
2020-03-19 11:03:08 +00:00
-- }}}
-- Keymap --------------------------------------- {{{
2020-03-20 15:40:53 +00:00
-- Default mappings that need to be removed
removedKeys :: [String]
removedKeys = ["M-S-c", "M-S-q"]
2020-03-19 11:03:08 +00:00
myKeys :: [(String, X ())]
2020-03-20 15:40:53 +00:00
myKeys = [ ("M-C-k", sendMessage MirrorExpand)
, ("M-C-j", sendMessage MirrorShrink)
2020-03-19 11:03:08 +00:00
, ("M-f", toggleFullscreen)
2020-03-20 15:40:53 +00:00
, ("M-S-C-c", kill1)
2020-03-19 11:03:08 +00:00
, ("M-S-C-a", windows copyToAll) -- windows: Modify the current window list with a pure function, and refresh
, ("M-C-c", killAllOtherCopies)
2020-03-20 15:40:53 +00:00
, ("M-S-C-q", io $ exitWith ExitSuccess)
2020-03-19 11:03:08 +00:00
-- programs
, ("M-p", spawn myLauncher)
, ("M-S-p", spawn "rofi -combi-modi drun,window -show combi")
2020-03-20 15:40:53 +00:00
, ("M-S-e", spawn "rofi -show emoji -modi emoji")
2020-03-19 11:03:08 +00:00
, ("M-b", spawn myBrowser)
2020-03-20 15:40:53 +00:00
, ("M-s", spawn $ scriptFile "rofi-search.sh")
, ("M-n", (spawn "echo 'n: terminal, h: ghci, w: WhatsApp' | dzen2 -p 1") >> scratchpadSubmap)
, ("M-e", promptExecute specialCommands)
2020-03-19 14:14:16 +00:00
] ++ copyToWorkspaceMappings
2020-03-19 11:03:08 +00:00
where
2020-03-19 14:14:16 +00:00
copyToWorkspaceMappings :: [(String, X())]
copyToWorkspaceMappings = [("M-C-" ++ wsp, windows $ copy wsp) | wsp <- map show [1..9]]
2020-03-19 11:03:08 +00:00
toggleFullscreen :: X ()
toggleFullscreen = do
sendMessage ToggleLayout -- toggle fullscreen layout
sendMessage ToggleStruts -- bar is hidden -> no need to make place for it
2020-03-20 15:40:53 +00:00
--sendMessage ToggleGaps -- show a small gap around the window
2020-03-19 11:03:08 +00:00
safeSpawn "polybar-msg" ["cmd", "toggle"] -- toggle polybar visibility
2020-03-20 15:40:53 +00:00
scratchpadSubmap :: X ()
scratchpadSubmap = submap $ M.fromList
[ ((myModMask, xK_n), namedScratchpadAction scratchpads "terminal")
, ((myModMask, xK_h), namedScratchpadAction scratchpads "ghci")
, ((myModMask, xK_w), namedScratchpadAction scratchpads "whatsapp") ]
2020-03-19 14:14:16 +00:00
specialCommands :: [(String, X ())]
specialCommands =
[ ("toggleSpacing", toggleWindowSpacingEnabled)
, ("toggleGaps", sendMessage ToggleGaps)
2020-03-20 15:40:53 +00:00
, ("screenshot", spawn $ scriptFile "screenshot.sh")
2020-03-19 14:14:16 +00:00
]
2020-03-20 15:40:53 +00:00
promptExecute :: [(String, X ())] -> X ()
promptExecute commands = do
selection <- Dmenu.menuMapArgs "rofi" ["-dmenu", "-i"] $ M.fromList commands -- -i -> case-insensitive
2020-03-19 14:14:16 +00:00
Maybe.fromMaybe (return ()) selection
2020-03-19 11:03:08 +00:00
-- }}}
-- ManageHook -------------------------------{{{
myManageHook :: Query (Data.Monoid.Endo WindowSet)
myManageHook = composeAll
[ resource =? "Dialog" --> doFloat ]
-- }}}
-- Main ------------------------------------ {{{
main = do
dbus <- D.connectSession
-- Request access to the DBus name
D.requestName dbus (D.busName_ "org.xmonad.Log")
[D.nameAllowReplacement, D.nameReplaceExisting, D.nameDoNotQueue]
2020-03-20 19:00:15 +00:00
-- $ ewmh (kills IntelliJ)
xmonad $ desktopConfig
2020-03-19 11:03:08 +00:00
{ terminal = myTerminal
, modMask = myModMask
, borderWidth = 1
, layoutHook = avoidStruts $ myLayout
, logHook = myLogHook <+> logHook desktopConfig <+> dynamicLogWithPP (polybarPP dbus)
, startupHook = myStartupHook <+> startupHook desktopConfig
2020-03-20 19:00:15 +00:00
, manageHook = manageDocks <+> myManageHook <+> (namedScratchpadManageHook scratchpads) <+> manageHook defaultConfig <+> (isFullscreen --> doF W.focusDown <+> doFullFloat)
2020-03-19 11:03:08 +00:00
, focusedBorderColor = aqua
, normalBorderColor = "#282828"
2020-03-20 15:40:53 +00:00
} `removeKeysP` removedKeys `additionalKeysP` myKeys
2020-03-19 11:03:08 +00:00
-- xmonad =<< statusBar myBar myPP toggleStrutsKey myConfig
-- }}}
-- POLYBAR Kram -------------------------------------- {{{
2020-03-19 13:14:18 +00:00
2020-03-19 11:03:08 +00:00
polybarPP :: D.Client -> PP
polybarPP dbus = namedScratchpadFilterOutWorkspacePP $ def
{ ppOutput = dbusOutput dbus
, ppCurrent = withBG bg2
, ppVisible = withBG bg2
, ppUrgent = withFG red
2020-03-20 19:00:15 +00:00
, ppLayout = removeWord "Hinted" . removeWord "Spacing" . withFG purple
2020-03-19 11:03:08 +00:00
, ppHidden = wrap " " " " . unwords . map wrapOpenWorkspaceCmd . words
, ppWsSep = ""
, ppSep = " | "
, ppExtras = []
2020-03-20 19:00:15 +00:00
, ppTitle = withFG aqua . (shorten 40)
2020-03-19 11:03:08 +00:00
}
where
removeWord substr = unwords . filter (/= substr) . words
withBG col = wrap ("%{B" ++ col ++ "} ") " %{B-}"
withFG col = wrap ("%{F" ++ col ++ "} ") " %{F-}"
wrapOpenWorkspaceCmd wsp
| all isDigit wsp = wrapOnClickCmd ("xdotool key super+" ++ wsp) wsp
| otherwise = wsp
wrapOnClickCmd cmd = wrap ("%{A1:" ++ cmd ++ ":}") "%{A}"
-- Emit a DBus signal on log updates
dbusOutput :: D.Client -> String -> IO ()
dbusOutput dbus str = do
let signal = (D.signal objectPath interfaceName memberName) {
D.signalBody = [D.toVariant $ UTF8.decodeString str]
}
D.emit dbus signal
where
objectPath = D.objectPath_ "/org/xmonad/Log"
interfaceName = D.interfaceName_ "org.xmonad.Log"
memberName = D.memberName_ "Update"
-- }}}
2020-03-19 13:14:18 +00:00