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

358 lines
14 KiB
Haskell
Raw Normal View History

{-# Language ScopedTypeVariables, LambdaCase #-}
2020-03-23 19:23:31 +00:00
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-unused-binds #-}
-- Imports -------------------------------------------------------- {{{
2020-03-22 18:40:50 +00:00
module Config (main) where
import qualified Rofi as Rofi
2020-03-22 18:40:50 +00:00
import Data.List (isSuffixOf, isPrefixOf, elem)
2020-03-25 10:05:44 +00:00
import Data.Char (isDigit)
import System.Exit (exitSuccess)
import qualified System.IO as SysIO
2020-03-22 18:06:44 +00:00
import qualified Data.Map as M
import qualified Data.Maybe as Maybe
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 ((|||))
import qualified XMonad.Util.Dmenu as Dmenu
import qualified XMonad.StackSet as W
import XMonad.Actions.CopyWindow
import XMonad.Actions.Submap
import XMonad.Config.Desktop
2020-03-25 10:05:44 +00:00
import XMonad.Layout.BinarySpacePartition
2020-03-22 18:06:44 +00:00
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.FadeInactive
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.EwmhDesktops (ewmh, fullscreenEventHook)
2020-03-22 18:06:44 +00:00
import XMonad.Hooks.SetWMName (setWMName)
import XMonad.Layout.Gaps
import XMonad.Layout.LayoutCombinators ((|||))
import XMonad.Layout.NoBorders -- for fullscreen without borders
import XMonad.Layout.ResizableTile -- for resizeable tall layout
2020-03-23 19:23:31 +00:00
import XMonad.Layout.MouseResizableTile
2020-03-25 10:05:44 +00:00
import XMonad.Layout.Spacing (spacingRaw, Border(..), toggleWindowSpacingEnabled)
2020-03-22 18:06:44 +00:00
import XMonad.Layout.Spiral
2020-03-23 19:23:31 +00:00
import XMonad.Layout.Renamed (renamed, Rename(Replace))
2020-03-22 18:06:44 +00:00
import XMonad.Layout.ThreeColumns -- for three column layout
import XMonad.Layout.ToggleLayouts
2020-03-23 19:23:31 +00:00
import XMonad.Layout.ZoomRow
2020-03-25 10:05:44 +00:00
import XMonad.Layout.BorderResize
2020-03-22 18:06:44 +00:00
import XMonad.Util.EZConfig (additionalKeysP, removeKeysP)
import XMonad.Util.NamedScratchpad
2020-03-23 19:23:31 +00:00
import XMonad.Util.Run
2020-03-22 18:06:44 +00:00
import XMonad.Util.SpawnOnce (spawnOnce)
2020-03-25 10:05:44 +00:00
import qualified XMonad.Actions.Navigation2D as Nav2d
-- Minimize stuff
import XMonad.Layout.Minimize
import qualified XMonad.Layout.BoringWindows as BoringWindows
import XMonad.Hooks.Minimize
import XMonad.Actions.Minimize
import XMonad.Actions.WindowBringer
import XMonad.Actions.Commands
2020-03-23 19:23:31 +00:00
-- }}}
2020-03-22 18:06:44 +00:00
-- Values -------------------- {{{
myModMask = mod4Mask
myLauncher = Rofi.asCommand def ["-show run"] -- "rofi -show run -theme /home/leon/scripts/rofi-scripts/launcher_grid_full_style.rasi"
2020-03-23 09:38:06 +00:00
myTerminal = "kitty --single-instance"
2020-03-22 18:06:44 +00:00
myBrowser = "google-chrome-stable"
--yBar = "xmobar"
--myXmobarPP= xmobarPP { ppCurrent = xmobarColor "#429942" "" . wrap "<" ">" }
2020-03-25 10:05:44 +00:00
{-| adds the scripts-directory path to the filename of a script |-}
scriptFile :: String -> String
scriptFile script = "/home/leon/scripts/" ++ script
2020-03-22 18:06:44 +00:00
scratchpads :: [NamedScratchpad]
2020-03-23 19:23:31 +00:00
scratchpads =
[ NS "terminal" launchTerminal (className =? "scratchpad_term") (customFloating $ W.RationalRect 0 0.7 1 0.3)
, NS "ghci" launchGHCI (className =? "scratchpad_ghci") (customFloating $ W.RationalRect 0 0.7 1 0.3)
2020-03-24 12:00:43 +00:00
, NS "spotify" "spotify" (appName =? "spotify") defaultFloating
, NS "discord" "discord" (appName =? "discord") defaultFloating
2020-03-23 19:23:31 +00:00
, NS "whatsapp" launchWhatsapp (("WhatsApp" `isSuffixOf`) <$> title) defaultFloating
, NS "slack" "slack" (("Slack | " `isPrefixOf`) <$> title) defaultFloating
2020-03-22 18:06:44 +00:00
]
2020-03-25 10:05:44 +00:00
where
2020-03-23 19:23:31 +00:00
launchTerminal = myTerminal ++ " --class scratchpad_term"
2020-03-25 10:05:44 +00:00
launchGHCI = myTerminal ++ " -e \"stack exec -- ghci\" --class scratchpad_ghci"
2020-03-23 19:23:31 +00:00
launchWhatsapp = "gtk-launch chrome-hnpfjngllnobngcgfapefoaidbinmjnm-Default.desktop"
2020-03-22 18:06:44 +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-23 19:23:31 +00:00
--layoutHints .
myLayout = BoringWindows.boringWindows . minimize . avoidStruts . smartBorders . toggleLayouts Full $ layouts
2020-03-23 19:23:31 +00:00
where
2020-03-25 14:33:33 +00:00
layouts =((rename "Tall" $ onlyGaps $ mouseResizableTile {draggerType = dragger}) -- ResizableTall 1 (3/100) (1/2) []
||| (rename "Horizon" $ onlyGaps $ mouseResizableTileMirrored {draggerType = dragger}) -- Mirror $ ResizableTall 1 (3/100) (3/4) []
||| (rename "Row" $ spacingAndGaps $ zoomRow)
||| (rename "Bsp" $ spacingAndGaps $ borderResize $ emptyBSP))
2020-03-25 10:05:44 +00:00
-- ||| (rename "threeCol" $ spacingAndGaps $ ThreeColMid 1 (3/100) (1/2))
-- ||| (rename "spiral" $ spacingAndGaps $ spiral (9/21))
-- ||| (rename "spiral" $ spiral (6/7)))
2020-03-23 19:23:31 +00:00
-- Grid
2020-03-25 10:05:44 +00:00
rename n = renamed [Replace n]
2020-03-23 19:23:31 +00:00
2020-03-25 10:05:44 +00:00
gap = 7
onlyGaps = gaps [ (dir, (gap*2)) | dir <- [L, R, D, U] ] -- gaps are included in mouseResizableTile
2020-03-25 14:33:33 +00:00
dragger = let x = fromIntegral gap * 2
in FixedDragger x x
spacingAndGaps = let intGap = fromIntegral gap
spacingBorder = Border intGap intGap intGap intGap
in onlyGaps . spacingRaw True spacingBorder False spacingBorder True
2020-03-23 19:23:31 +00:00
2020-03-22 18:06:44 +00:00
-- }}}
-- Loghook -------------------------------------- {{{
myLogHook :: X ()
2020-03-25 10:05:44 +00:00
myLogHook = fadeInactiveLogHook 0.95 -- opacity of unfocused windows
2020-03-22 18:40:50 +00:00
2020-03-22 18:06:44 +00:00
-- }}}
-- Startuphook ----------------------------- {{{
2020-03-22 18:40:50 +00:00
myStartupHook :: X ()
2020-03-22 18:06:44 +00:00
myStartupHook = do
spawnOnce "picom --config ~/.config/picom.conf --no-fading-openclose"
spawnOnce "pasystray"
spawn "/home/leon/.config/polybar/launch.sh"
setWMName "LG3D" -- Java stuff hack
-- }}}
-- Keymap --------------------------------------- {{{
2020-03-22 18:40:50 +00:00
-- Default mappings that need to be removed removedKeys :: [String]
2020-03-22 18:06:44 +00:00
removedKeys = ["M-S-c", "M-S-q"]
myKeys :: [(String, X ())]
2020-03-25 10:05:44 +00:00
myKeys = [ ("M-C-k", sendMessage MirrorExpand >> sendMessage ShrinkSlave )
, ("M-C-j", sendMessage MirrorShrink >> sendMessage ExpandSlave )
, ("M-+", sendMessage zoomIn)
, ("M--", sendMessage zoomOut)
, ("M-#", sendMessage zoomReset)
, ("M-f", toggleFullscreen)
, ("M-S-C-c", kill1)
, ("M-S-C-a", windows copyToAll) -- windows: Modify the current window list with a pure function, and refresh
, ("M-C-c", killAllOtherCopies)
, ("M-S-C-q", io $ exitSuccess)
2020-03-22 18:06:44 +00:00
-- programs
2020-03-25 10:05:44 +00:00
, ("M-p", spawn myLauncher)
, ("M-b", spawn myBrowser)
, ("M-S-p", Rofi.showCombi def [ "drun", "window", "ssh" ])
, ("M-S-e", Rofi.showNormal def "emoji" )
2020-03-25 10:05:44 +00:00
, ("M-s", spawn $ scriptFile "rofi-search.sh")
, ("M-S-s", spawn $ "cat " ++ scriptFile "bookmarks"
++ " | " ++ Rofi.asCommand def ["-dmenu", "-p open"]
++ " | bash")
, ("M-n", scratchpadSubmap )
, ("M-m", mediaSubmap )
, ("M-e", Rofi.promptRunCommand specialCommands)
, ("M-C-e", Rofi.promptRunCommand =<< defaultCommands )
2020-03-25 10:05:44 +00:00
-- BSP
, ("M-M1-h", sendMessage $ ExpandTowards L)
, ("M-M1-l", sendMessage $ ExpandTowards R)
, ("M-M1-k", sendMessage $ ExpandTowards U)
, ("M-M1-j", sendMessage $ ExpandTowards D)
, ("M-<Backspace>", sendMessage $ Swap)
, ("M-M1-<Backspace>", sendMessage $ Rotate)
2020-03-25 10:05:44 +00:00
, ("M-S-M1-h", Nav2d.windowGo L False)
, ("M-S-M1-l", Nav2d.windowGo R False)
, ("M-S-M1-k", Nav2d.windowGo U False)
, ("M-S-M1-j", Nav2d.windowGo D False)
2020-03-22 18:06:44 +00:00
-- Minimization
, ("M-k", BoringWindows.focusUp)
, ("M-j", BoringWindows.focusDown)
, ("M-ü", withFocused minimizeWindow)
, ("M-S-ü", withLastMinimized maximizeWindow)
, ("M-C-ü", promptRestoreWindow)
, ("M1-<Tab>", cycleMinimizedWindow)
2020-03-22 18:06:44 +00:00
] ++ copyToWorkspaceMappings
where
copyToWorkspaceMappings :: [(String, X())]
copyToWorkspaceMappings = [("M-C-" ++ wsp, windows $ copy wsp) | wsp <- map show [1..9]]
cycleMinimizedWindow :: X ()
cycleMinimizedWindow = withLastMinimized $ \window -> do
withFocused minimizeWindow
maximizeWindowAndFocus window
promptRestoreWindow = do
wm <- windowMap
shownWindows <- withMinimized (\minimizedWindows -> pure $ M.filter (`elem` minimizedWindows) wm)
w <- Rofi.promptSimple def (M.keys shownWindows)
whenJust (M.lookup w wm) (\w -> maximizeWindow w >> (windows $ bringWindow w))
2020-03-22 18:06:44 +00:00
toggleFullscreen :: X ()
toggleFullscreen = do
sendMessage ToggleLayout -- toggle fullscreen layout
sendMessage ToggleStruts -- bar is hidden -> no need to make place for it
--sendMessage ToggleGaps -- show a small gap around the window
safeSpawn "polybar-msg" ["cmd", "toggle"] -- toggle polybar visibility
2020-03-22 18:06:44 +00:00
scratchpadSubmap :: X ()
2020-03-24 12:00:43 +00:00
scratchpadSubmap = describedSubmap "Scratchpads"
[ ((myModMask, xK_n), "<M-n> terminal", namedScratchpadAction scratchpads "terminal")
, ((myModMask, xK_h), "<M-h> ghci", namedScratchpadAction scratchpads "ghci")
, ((myModMask, xK_w), "<M-w> whatsapp", namedScratchpadAction scratchpads "whatsapp")
, ((myModMask, xK_s), "<M-s> slack", namedScratchpadAction scratchpads "slack")
, ((myModMask, xK_m), "<M-m> spotify", namedScratchpadAction scratchpads "spotify")
, ((myModMask, xK_d), "<M-m> discord", namedScratchpadAction scratchpads "discord")
]
mediaSubmap :: X ()
2020-03-24 12:00:43 +00:00
mediaSubmap = describedSubmap "Media"
2020-03-25 10:05:44 +00:00
[ ((myModMask, xK_m), "<M-m> play/pause", spawn "playerctl play-pause")
, ((myModMask, xK_l), "<M-l> next", spawn "playerctl next")
, ((myModMask, xK_l), "<M-h> previous", spawn "playerctl previous")
, ((myModMask, xK_k), "<M-k> increase volume", spawn "amixer sset Master 5%+")
, ((myModMask, xK_j), "<M-j> decrease volume", spawn "amixer sset Master 5%-")
]
2020-03-23 19:23:31 +00:00
2020-03-22 18:06:44 +00:00
specialCommands :: [(String, X ())]
specialCommands =
2020-03-25 10:05:44 +00:00
[ ("screenshot", spawn $ scriptFile "screenshot.sh")
, ("toggleSpacing", toggleWindowSpacingEnabled)
2020-03-22 18:06:44 +00:00
, ("toggleGaps", sendMessage ToggleGaps)
]
2020-03-24 12:00:43 +00:00
describedSubmap :: String -> [((KeyMask, KeySym), String, X ())] -> X ()
2020-03-25 10:05:44 +00:00
describedSubmap submapTitle mappings = promptDzenWhileRunning submapTitle descriptions mySubmap
where
2020-03-25 10:05:44 +00:00
mySubmap = submap $ M.fromList $ map (\(k, _, f) -> (k, f)) mappings
descriptions = map (\(_,x,_) -> x) mappings
2020-03-22 18:06:44 +00:00
-- }}}
-- ManageHook -------------------------------{{{
myManageHook :: Query (Data.Monoid.Endo WindowSet)
myManageHook = composeAll
2020-03-22 18:40:50 +00:00
[ resource =? "Dialog" --> doFloat
2020-03-25 10:05:44 +00:00
, appName =? "pavucontrol" --> doFloat
2020-03-23 19:23:31 +00:00
-- , isFullscreen --> doF W.focusDown <+> doFullFloat
, manageDocks
, namedScratchpadManageHook scratchpads
2020-03-22 18:40:50 +00:00
]
2020-03-22 18:06:44 +00:00
-- }}}
-- Main ------------------------------------ {{{
2020-03-22 18:40:50 +00:00
main :: IO ()
2020-03-22 18:06:44 +00:00
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-25 10:05:44 +00:00
2020-03-22 18:06:44 +00:00
-- $ ewmh (kills IntelliJ)
2020-03-25 10:05:44 +00:00
xmonad
$ ewmh
$ Nav2d.withNavigation2DConfig def { Nav2d.defaultTiledNavigation = Nav2d.sideNavigation }
$ desktopConfig
{ terminal = myTerminal
, modMask = myModMask
, borderWidth = 1
, layoutHook = myLayout
, logHook = myLogHook <+> dynamicLogWithPP (polybarPP dbus) <+> logHook def
, startupHook = myStartupHook <+> startupHook def
, manageHook = myManageHook <+> manageHook def
-- , handleEventHook = minimizeEventHook <+> handleEventHook def -- fullscreenEventHook
2020-03-25 10:05:44 +00:00
, focusedBorderColor = aqua
, normalBorderColor = "#282828"
} `removeKeysP` removedKeys `additionalKeysP` myKeys
2020-03-22 18:06:44 +00:00
-- }}}
-- POLYBAR Kram -------------------------------------- {{{
polybarPP :: D.Client -> PP
polybarPP dbus = namedScratchpadFilterOutWorkspacePP $ def
{ ppOutput = dbusOutput dbus
, ppCurrent = withBG bg2
2020-03-23 19:23:31 +00:00
, ppVisible = withBG bg2
2020-03-22 18:06:44 +00:00
, ppUrgent = withFG red
2020-03-25 14:33:33 +00:00
, ppLayout = removeWord "Minimize" . removeWord "Hinted" . removeWord "Spacing" . withFG purple
2020-03-22 18:06:44 +00:00
, ppHidden = wrap " " " " . unwords . map wrapOpenWorkspaceCmd . words
, ppWsSep = ""
, ppSep = " | "
, ppExtras = []
, ppTitle = withFG aqua . (shorten 40)
}
where
2020-03-23 19:23:31 +00:00
removeWord substr = unwords . filter (/= substr) . words
2020-03-22 18:06:44 +00:00
withBG col = wrap ("%{B" ++ col ++ "} ") " %{B-}"
withFG col = wrap ("%{F" ++ col ++ "} ") " %{F-}"
2020-03-23 19:23:31 +00:00
wrapOpenWorkspaceCmd wsp
2020-03-22 18:06:44 +00:00
| all isDigit wsp = wrapOnClickCmd ("xdotool key super+" ++ wsp) wsp
| otherwise = wsp
wrapOnClickCmd command = wrap ("%{A1:" ++ command ++ ":}") "%{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-23 19:23:31 +00:00
2020-03-25 10:05:44 +00:00
-- Utilities --------------------------------------------------- {{{
promptDzenWhileRunning :: String -> [String] -> X () -> X ()
promptDzenWhileRunning promptTitle options action = do
handle <- spawnPipe $ "sleep 1 && dzen2 -e onstart=uncollapse -l " ++ lineCount ++ " -fn '" ++ font ++ "'"
io $ SysIO.hPutStrLn handle (promptTitle ++ unlines options)
_ <- action
io $ SysIO.hClose handle
where
lineCount = show $ length options
font = "-*-iosevka-medium-r-s*--16-87-*-*-*-*-iso10???-1"
-- }}}