xmonad/xmonad.hs

272 lines
10 KiB
Haskell

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
import Control.Arrow (second)
import Control.Monad (liftM2)
import Data.List (isInfixOf)
import qualified Data.Monoid
import Data.Ratio
import XMonad
( ChangeLayout (NextLayout),
Default (def),
Full (Full),
Mirror (Mirror),
Query,
Rectangle (Rectangle),
Tall (Tall),
WindowSet,
WindowSpace,
X,
XConfig
( borderWidth,
focusedBorderColor,
layoutHook,
logHook,
manageHook,
modMask,
normalBorderColor,
startupHook,
terminal,
workspaces
),
className,
composeAll,
doF,
doFloat,
doIgnore,
doShift,
handleEventHook,
mod4Mask,
resource,
sendMessage,
spawn,
title,
withWindowSet,
xmonad,
(-->),
(<&&>),
(<+>),
(=?),
(|||),
)
import XMonad.Actions.WindowGo (raise, runOrRaise)
import XMonad.Hooks.DynamicLog
( PP
( ppCurrent,
ppExtras,
ppHidden,
ppHiddenNoWindows,
ppOrder,
ppSep,
ppSort,
ppTitleSanitize,
ppUrgent
),
ppVisible,
shorten,
wrap,
xmobarBorder,
xmobarColor,
xmobarRaw,
xmobarStrip,
)
import XMonad.Hooks.EwmhDesktops
( ewmh,
ewmhFullscreen,
)
import XMonad.Hooks.InsertPosition (Focus (Newer), Position (End), insertPosition)
import XMonad.Hooks.ManageHelpers (doRectFloat)
import XMonad.Hooks.Place (placeHook, simpleSmart)
import XMonad.Hooks.SetWMName (setWMName)
import XMonad.Hooks.StatusBar
( defToggleStrutsKey,
statusBarProp,
withEasySB,
)
import XMonad.Layout (Resize (Expand, Shrink))
import XMonad.Layout.Fullscreen (fullscreenEventHook)
import XMonad.Layout.LayoutModifier
import qualified XMonad.Layout.LayoutModifier
import XMonad.Layout.Named (named)
import XMonad.Layout.NoBorders
import XMonad.Layout.ResizableTile (MirrorResize (MirrorExpand), ResizableTall (ResizableTall))
import XMonad.Layout.Spacing
( Border (Border),
Spacing,
spacingRaw,
)
import XMonad.Layout.WindowNavigation
( Direction2D (L, R),
Navigate (Go),
windowNavigation,
)
import XMonad.StackSet (RationalRect (RationalRect), Stack (Stack), Workspace (tag), currentTag, greedyView, integrate', shift, stack)
import XMonad.Util.EZConfig (additionalKeysP)
import XMonad.Util.Font (fi)
import XMonad.Util.Loggers (logTitles, wrapL)
import XMonad.Util.SpawnOnce (spawnOnce)
import XMonad.Util.Ungrab (unGrab)
import XMonad.Util.WorkspaceCompare (getSortByIndex)
main :: IO ()
main = do
colors <- getWalColors
xmonad . ewmhFullscreen . ewmh
. withEasySB (statusBarProp "xmobar ~/.config/xmobar/xmobarrc" (pure $ myXmobarPP colors)) defToggleStrutsKey
$ def
{ modMask = mod4Mask,
terminal = "st",
startupHook = myStartupHook,
borderWidth = 2,
normalBorderColor = "#000000",
focusedBorderColor = colors !! 7,
workspaces = myWorkspaces,
manageHook = myManageHook,
layoutHook = myLayout,
handleEventHook =
handleEventHook def <+> fullscreenEventHook
}
`additionalKeysP` [ ("M-S-z", spawn "xscreensaver-command -lock"),
("M-S-s", unGrab *> spawn "cast_screenshot"),
("M-f", runOrRaise "brave" (className =? "Brave-browser")),
("M-i", raise (className =? "jetbrains-idea")),
("M-<Space>", spawn "rofi -show drun"),
("M-p", spawn "dmenu-with-suggestions"),
-- audio settings
("<XF86AudioLowerVolume>", spawn "amixer set Master 5%- unmute"),
("<XF86AudioRaiseVolume>", spawn "amixer set Master 5%+ unmute"),
("<XF86AudioMute>", spawn "amixer set Master toggle"),
("<XF86AudioPlay>", spawn "playerctl play-pause"),
("<XF86AudioPrev>", spawn "playerctl previous"),
("<XF86AudioNext>", spawn "playerctl next"),
-- window navigation
("M-l", sendMessage $ Go R),
("M-h", sendMessage $ Go L),
("M-S-h", sendMessage Shrink), -- Shrink horiz window width
("M-S-l", sendMessage Expand), -- Expand horiz window width
-- layout switching
("M-<Tab>", sendMessage NextLayout),
-- dmenu stuff
("M1-<F4>", spawn "powerbutton"),
-- lockscreen
("M-<Escape>", spawn "betterlockscreen -l")
]
myXmobarPP :: [String] -> PP
myXmobarPP colors =
def
{ ppSep = walXmobarColor 1 " \63617 ",
ppTitleSanitize = xmobarStrip,
ppCurrent = wrap " " "" . xmobarBorder "Top" (colors !! 6) 2,
ppHidden = white . wrap " " "",
ppHiddenNoWindows = lowWhite . wrap " " "",
ppUrgent = red . wrap (yellow "!") (yellow "!"),
ppVisible = wrap " " "" . xmobarBorder "Bottom" (colors !! 6) 2,
ppOrder = \[ws, l, _, wins] -> [ws, l, wins],
ppExtras = [logTitles formatFocused formatUnfocused],
ppSort = hideWorkspaces
}
where
formatFocused = wrap (walXmobarColor 7 "<fn=2>\58279</fn>") (walXmobarColor 7 "<fn=2>\58254</fn>") . walXmobarColor 7 . ppWindow
formatUnfocused = wrap (walXmobarColor 4 "<fn=2>\58279</fn>") (walXmobarColor 4 "<fn=2>\58254</fn>") . walXmobarColor 4 . ppWindow
walXmobarColor index = xmobarColor (colors !! index) ""
ppWindow :: String -> String
ppWindow = xmobarRaw . (\w -> if null w then "untitled" else w) . shorten 30
lowWhite, red, white, yellow :: String -> String
white = xmobarColor "#f8f8f2" ""
yellow = xmobarColor "#f1fa8c" ""
red = xmobarColor "#ff5555" ""
lowWhite = xmobarColor "#bbbbbb" ""
hideWorkspaces = do
sortByIndex <- getSortByIndex
wsfilter <- thefilter
return (wsfilter . sortByIndex)
where
thefilter :: X ([WindowSpace] -> [WindowSpace])
--thefilter = filter ( not . isEmptyWs) . sortworkspaces
thefilter = do
currentWS <- withWindowSet (pure . currentTag)
return $ reverse . dropWhile (liftM2 (&&) ((currentWS /=) . tag) isEmptyWs) . reverse
isEmptyWs workspace = null $ integrate' $ stack workspace
myStartupHook :: X ()
myStartupHook = do
spawnOnce "picom &"
spawnOnce "sh $HOME/.fehbg"
spawnOnce "setxkbmap -option caps:escape"
getWalColors :: IO [String]
getWalColors = do
let file = "/home/qv/.cache/wal/colors"
contents <- readFile file
let colors = lines contents
return (colors ++ replicate (16 - length colors) "#000000")
mySpacing' :: Integer -> l a -> XMonad.Layout.LayoutModifier.ModifiedLayout Spacing l a
mySpacing' i = spacingRaw True (Border i 0 i i) True (Border i 0 i i) True
--myWorkspaces = [" dev ", " www ", " sys ", " doc ", " vbox ", " chat ", " mus ", " vid ", " gfx "]
myWorkspaces :: [String]
myWorkspaces = show <$> ([1 .. 9] :: [Integer])
myLayout = smartBorders $ windowNavigation tiled ||| smartBorders Full ||| Mirror (fullWSpacing 8 $ Tall nmaster delta ratio)
where
tiled = named "Tall" $ mySpacing' 8 $ Tall nmaster delta ratio
nmaster = 1 -- Default number of windows in the master pane
ratio = 1 / 2 -- Default proportion of screen occupied by master pane
delta = 3 / 100 -- Percent of screen to increment by when resizing panes
myManageHook :: XMonad.Query (Data.Monoid.Endo WindowSet)
myManageHook =
composeAll
-- 'doFloat' forces a window to float. Useful for dialog boxes and such.
-- using 'doShift ( myWorkspaces !! 7)' sends program to workspace 8!
-- I'm doing it this way because otherwise I would have to write out the full
-- name of my workspaces and the names would be very long if using clickable workspaces.
[ className =? "confirm" --> doFloat,
className =? "file_progress" --> doFloat,
className =? "dialog" --> doFloat,
className =? "download" --> doFloat,
className =? "error" --> doFloat,
className =? "Gimp" --> doFloat,
className =? "notification" --> doFloat,
className =? "pinentry-gtk-2" --> doFloat,
className =? "splash" --> doFloat,
className =? "toolbar" --> doFloat,
title =? "Oracle VM VirtualBox Manager" --> doFloat,
title =? "Mozilla Firefox" --> viewShift (myWorkspaces !! 1),
title =? "Signal" --> viewShift (myWorkspaces !! 2),
className =? "TelegramDesktop" --> viewShift (myWorkspaces !! 2),
className =? "Element" --> viewShift (myWorkspaces !! 2),
className =? "Thunderbird" --> viewShift (myWorkspaces !! 2),
className =? "Gimp" --> doShift (myWorkspaces !! 8),
(className =? "firefox" <&&> resource =? "Dialog") --> doFloat, -- Float Firefox Dialog
className =? "alfaview" --> viewShift (myWorkspaces !! 3),
className =? "jetbrains-idea" --> viewShift (myWorkspaces !! 4),
className =? "jetbrains-code-with-me-guest" --> viewShift (myWorkspaces !! 4),
(className =? "jetbrains-studio") <&&> (title ~=? "win") --> doIgnore,
(className =? "TelegramDesktop") <&&> (title ~=? "Media viewer") --> doFloat
]
<+> insertPosition End Newer
where
viewShift = doF . liftM2 (.) greedyView shift
-- IntelliJ fix
(~=?) :: Eq a => Query [a] -> [a] -> Query Bool
q ~=? x = fmap (isInfixOf x) q
fullWSpacing :: Int -> l a -> ModifiedLayout FullWSpacing l a
fullWSpacing p = ModifiedLayout (FullWSpacing p)
data FullWSpacing a = FullWSpacing Int deriving (Show, Read)
instance LayoutModifier FullWSpacing a where
pureModifier (FullWSpacing _) _ (Just (Stack f _ _)) [(param, rect)] = ([(param, shrinkRect 250 rect)], Nothing)
pureModifier (FullWSpacing p) _ _ wrs = (map (second $ shrinkRect p) wrs, Nothing)
modifierDescription (FullWSpacing p) = "Tall center"
shrinkRect :: Int -> Rectangle -> Rectangle
shrinkRect p (Rectangle x y w h) = Rectangle (x + fi (p `div` 2)) (y + fi p) (fi $ max 1 $ fi w -2 * (p `div` 2)) (fi $ max 1 $ fi h -2 * p)