1080 lines
35 KiB
Haskell
Raw Normal View History

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeSynonymInstances #-}
2021-08-05 16:41:19 -06:00
{-# LANGUAGE TupleSections #-}
2021-08-05 17:32:25 -06:00
{-# LANGUAGE PartialTypeSignatures #-}
module Main where
import Codec.Binary.UTF8.String as UTF8
2017-09-20 16:28:26 -07:00
import qualified Codec.Binary.UTF8.String as UTF8String (encode)
import qualified Control.Arrow as A
2016-11-24 18:33:49 -08:00
import Control.Monad
2018-06-14 15:57:27 -07:00
import Control.Monad.Trans.Class
2016-11-24 18:33:49 -08:00
import Control.Monad.Trans.Maybe
import Data.Aeson
import qualified Data.ByteString.Lazy as B
2019-06-23 21:24:30 -07:00
import Data.Char
import Data.Foldable
2016-11-24 18:33:49 -08:00
import Data.List
import Data.List.Split
import qualified Data.Map as M
2016-11-24 18:33:49 -08:00
import Data.Maybe
import Data.Monoid
import qualified Data.MultiMap as MM
import Data.Proxy
2017-09-20 16:28:26 -07:00
import Data.Tuple.Sequence (sequenceT)
import Data.Typeable
import Foreign.C.Types
2016-11-24 18:33:49 -08:00
import Graphics.X11.ExtraTypes.XF86
import Network.HostName
import Safe
2016-11-24 18:33:49 -08:00
import System.Directory
2019-06-24 18:59:57 -07:00
import System.Environment.XDG.DesktopEntry
2016-11-24 18:33:49 -08:00
import System.FilePath.Posix
2019-06-23 21:24:30 -07:00
import System.IO.Unsafe
2017-05-07 23:35:01 -07:00
import System.Process
2016-11-24 18:33:49 -08:00
import Text.Printf
import Unsafe.Coerce
2016-11-24 18:33:49 -08:00
import XMonad hiding ( (|||) )
2016-11-29 11:28:17 -08:00
import XMonad.Actions.CycleWS hiding (nextScreen)
2017-04-14 19:21:54 -07:00
import XMonad.Actions.CycleWorkspaceByScreen
2016-10-23 01:57:08 -07:00
import qualified XMonad.Actions.DynamicWorkspaceOrder as DWO
2017-09-09 19:40:13 -07:00
import XMonad.Actions.DynamicWorkspaces hiding (withWorkspace, renameWorkspace)
2016-11-24 18:33:49 -08:00
import XMonad.Actions.Minimize
2017-05-19 00:52:37 -07:00
import XMonad.Actions.Navigation2D
import qualified XMonad.Actions.SwapWorkspaces as SW
import XMonad.Actions.UpdatePointer
2016-11-24 18:33:49 -08:00
import XMonad.Actions.WindowBringer
import XMonad.Actions.WindowGo
import XMonad.Actions.WorkspaceNames
2016-11-24 18:33:49 -08:00
import XMonad.Config ()
2021-08-01 00:34:51 -06:00
import XMonad.Core (getDirectories)
import XMonad.Hooks.DynamicProperty
2016-11-24 18:33:49 -08:00
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.FadeInactive
2022-01-27 21:45:58 -07:00
import XMonad.Hooks.Focus hiding (currentWorkspace)
2016-11-24 18:33:49 -08:00
import XMonad.Hooks.ManageDocks
2017-03-10 15:09:28 -08:00
import XMonad.Hooks.ManageHelpers
2016-11-26 22:10:11 -08:00
import XMonad.Hooks.Minimize
2021-08-01 00:34:51 -06:00
import XMonad.Hooks.TaffybarPagerHints
2017-04-14 19:21:54 -07:00
import XMonad.Hooks.WorkspaceHistory
2016-11-24 18:33:49 -08:00
import XMonad.Layout.Accordion
import XMonad.Layout.BoringWindows
import XMonad.Layout.ConditionalLayout
2016-12-28 21:38:27 -08:00
import XMonad.Layout.Cross
2021-08-21 13:48:33 -06:00
import XMonad.Layout.Decoration
2021-08-03 14:01:39 -06:00
import XMonad.Layout.Grid
2016-11-24 18:33:49 -08:00
import XMonad.Layout.LayoutCombinators
import XMonad.Layout.LayoutModifier
import XMonad.Layout.LimitWindows
import XMonad.Layout.MagicFocus
2021-08-03 13:03:23 -06:00
import XMonad.Layout.Magnifier hiding (Toggle)
2016-11-24 18:33:49 -08:00
import XMonad.Layout.Minimize
import XMonad.Layout.MultiColumns
import XMonad.Layout.MultiToggle
import XMonad.Layout.MultiToggle.Instances
import XMonad.Layout.NoBorders
2016-11-20 21:05:40 -08:00
import qualified XMonad.Layout.Renamed as RN
2016-11-24 18:33:49 -08:00
import XMonad.Layout.Spacing
2017-01-04 16:35:51 -08:00
import XMonad.Layout.Tabbed
2021-08-01 00:34:51 -06:00
import XMonad.Main (launch)
2021-08-03 13:03:23 -06:00
import qualified XMonad.Operations
import qualified XMonad.StackSet as W
2016-11-24 18:33:49 -08:00
import XMonad.Util.CustomKeys
import qualified XMonad.Util.Dmenu as DM
import qualified XMonad.Util.ExtensibleState as XS
2016-11-24 18:33:49 -08:00
import XMonad.Util.Minimize
import XMonad.Util.NamedScratchpad as NS
2016-11-24 18:33:49 -08:00
import XMonad.Util.NamedWindows (getName)
import XMonad.Util.Run
import XMonad.Util.WorkspaceCompare
myConfig = def
{ modMask = mod4Mask
2021-07-12 18:12:20 -06:00
, terminal = "alacritty"
, manageHook
= namedScratchpadManageHook scratchpads
, layoutHook = myLayoutHook
2021-08-04 10:23:35 -06:00
, borderWidth = 0
, logHook
= updatePointer (0.5, 0.5) (0, 0)
<> toggleFadeInactiveLogHook 0.9
<> workspaceHistoryHook
<> setWorkspaceNames
<> logHook def
, handleEventHook
= followIfNoMagicFocus
<> minimizeEventHook
-- <> restartEventHook
<> myScratchPadEventHook
, startupHook = myStartup
, keys = customKeys (const []) addKeys
}
2021-08-03 10:49:05 -06:00
2021-08-21 13:48:33 -06:00
gothamTheme =
def
{ inactiveBorderColor = "#000"
, activeBorderColor = "#edb443"
, activeColor = "#edb443"
, inactiveColor = "#091f2e"
, inactiveTextColor = "#edb443"
, activeTextColor = "#091f2e"
, fontName = "xft:Source Code Pro:style=Semibold"
, decoHeight = 25
}
2021-08-03 10:49:05 -06:00
restartEventHook e@ClientMessageEvent { ev_message_type = mt } = do
a <- getAtom "XMONAD_RESTART"
2021-08-05 16:41:19 -06:00
if mt == a
2021-08-03 10:49:05 -06:00
then XMonad.Operations.restart "imalison-xmonad" True >> return (All True)
else return $ All True
restartEventHook _ = return $ All True
2017-07-24 11:39:02 -07:00
myNavigation2DConfig = def { defaultTiledNavigation = centerNavigation }
main =
xmonad
. docks
. pagerHints
2022-01-27 21:45:58 -07:00
. setEwmhActivateHook activateSwitchWs
. ewmh
. ewmhFullscreen
. withNavigation2DConfig myNavigation2DConfig $ myConfig
2021-07-13 03:37:03 -06:00
-- Utility functions
2017-04-14 19:21:54 -07:00
-- Log to a file from anywhere
writeToHomeDirLog stuff = io $ getLogFile >>= flip appendFile (stuff ++ "\n")
where getLogFile = (</> "temp" </> "xmonad.log") <$> getHomeDirectory
logWindowSet message =
withWindowSet $ \ws -> writeToHomeDirLog $ printf "%s -- " message $ show ws
2017-05-07 23:35:01 -07:00
xRunCommand cmd = void $ io $ readCreateProcess (shell cmd) ""
2017-03-31 22:34:47 -07:00
(<..>) :: Functor f => (a -> b) -> f (f a) -> f (f b)
(<..>) = fmap . fmap
2016-11-29 15:46:51 -08:00
2016-11-25 18:39:27 -08:00
forkM :: Monad m => (i -> m a) -> (i -> m b) -> i -> m (a, b)
2017-09-20 16:28:26 -07:00
forkM a b = sequenceT . (a A.&&& b)
tee :: Monad m => (i -> m a) -> (i -> m b) -> i -> m a
2016-11-25 18:39:27 -08:00
tee = (fmap . fmap . fmap) (fmap fst) forkM
(>>=/) :: Monad m => m a -> (a -> m b) -> m a
(>>=/) a = (a >>=) . tee return
findM :: (Monad m) => (a -> m (Maybe b)) -> [a] -> m (Maybe b)
findM f = runMaybeT . msum . map (MaybeT . f)
if' :: Bool -> a -> a -> a
if' True x _ = x
if' False _ y = y
ifL :: a -> a -> Bool -> a
ifL a b c = if' c a b
2017-04-12 18:00:01 -07:00
infixl 4 <$$>
(<$$>) :: Functor f => f (a -> b) -> a -> f b
functor <$$> value = ($ value) <$> functor
toggleInMap' :: Ord k => Bool -> k -> M.Map k Bool -> M.Map k Bool
toggleInMap' d k m =
let existingValue = M.findWithDefault d k m
2016-11-25 18:56:07 -08:00
in M.insert k (not existingValue) m
toggleInMap :: Ord k => k -> M.Map k Bool -> M.Map k Bool
toggleInMap = toggleInMap' True
maybeRemap k = M.findWithDefault k k
2016-11-26 18:04:48 -08:00
(<$.>) :: Functor f => (b -> c) -> (a -> f b) -> a -> f c
(<$.>) l r = fmap l . r
2016-11-29 15:46:08 -08:00
withFocusedR f = withWindowSet (f . W.peek)
withFocusedD d f = maybe (return d) f <$> withWindowSet (return . W.peek)
2016-11-29 20:19:48 -08:00
withWorkspaceR f = withWindowSet $ f . W.workspace . W.current
mapP = mapP' id
2016-11-29 20:19:48 -08:00
mapP' f f' = map (f A.&&& f')
minimizedWindows = withMinimized return
2017-03-31 22:34:47 -07:00
visibleWindows =
(\\) <$> withWorkspaceR (return . W.integrate' . W.stack)
<*> minimizedWindows
2017-05-19 00:52:37 -07:00
followingWindow action = do
orig <- withWindowSet (return . W.peek)
res <- action
2017-05-30 14:48:52 -07:00
whenJust orig $ windows . W.focusWindow
return res
2019-06-23 21:24:30 -07:00
myDmenuArgs = ["-dmenu", "-i", "-show-icons"]
myDmenu = DM.menuArgs "rofi" myDmenuArgs
getWorkspaceDmenu = myDmenu (workspaces myConfig)
2016-11-09 17:29:45 -08:00
-- Selectors
2017-05-30 19:24:04 -07:00
isGmailTitle t = isInfixOf "@gmail.com" t && isInfixOf "Gmail" t
isMessagesTitle = isPrefixOf "Messages"
isChromeClass = isInfixOf "chrome"
noSpecialChromeTitles = helper <$> title
where helper t = not $ any ($ t) [isGmailTitle, isMessagesTitle]
chromeSelectorBase = isChromeClass <$> className
2016-11-21 15:52:23 -08:00
chromeSelector = chromeSelectorBase <&&> noSpecialChromeTitles
elementSelector = className =? "Element"
2016-10-26 15:19:49 -07:00
emacsSelector = className =? "Emacs"
2017-05-30 19:24:04 -07:00
gmailSelector = chromeSelectorBase <&&> fmap isGmailTitle title
messagesSelector = chromeSelectorBase <&&> isMessagesTitle <$> title
slackSelector = className =? "Slack"
spotifySelector = className =? "Spotify"
transmissionSelector = fmap (isPrefixOf "Transmission") title
volumeSelector = className =? "Pavucontrol"
2016-10-26 15:19:49 -07:00
virtualClasses =
[ (gmailSelector, "Gmail")
, (messagesSelector, "Messages")
, (chromeSelector, "Chrome")
, (transmissionSelector, "Transmission")
]
2016-11-09 17:29:45 -08:00
2016-11-21 23:45:30 -06:00
-- Commands
2021-08-03 11:30:19 -06:00
chromeCommand = "google-chrome-stable"
elementCommand = "element-desktop"
2016-11-21 23:45:30 -06:00
emacsCommand = "emacsclient -c"
gmailCommand =
"google-chrome-stable --new-window https://mail.google.com/mail/u/0/#inbox"
2021-08-02 06:55:43 -06:00
htopCommand = "alacritty --title htop -e htop"
messagesCommand =
"google-chrome-stable --new-window https://messages.google.com/web/conversations"
slackCommand = "slack"
spotifyCommand = "spotify"
2016-11-21 23:45:30 -06:00
transmissionCommand = "transmission-gtk"
volumeCommand = "pavucontrol"
2016-11-21 23:45:30 -06:00
-- Startup hook
hostNameToAction =
2021-08-05 17:32:25 -06:00
M.fromList [ ("ryzen-shine", return ())
]
myStartup = do
2021-08-09 14:10:30 -06:00
setToggleActiveAll AVOIDSTRUTS True
2021-08-03 11:30:19 -06:00
setToggleActiveAll GAPS True
setToggleActiveAll NOBORDERS True
hostName <- io getHostName
M.findWithDefault (return ()) hostName hostNameToAction
2016-11-09 17:29:45 -08:00
2021-08-05 17:32:25 -06:00
-- Magnify
data DisableOnTabbedCondition = DisableOnTabbedCondition deriving (Read, Show)
instance ModifierCondition DisableOnTabbedCondition where
shouldApply _ workspaceId = fromMaybe True <$> final
where allWorkspaces = withWindowSet $ return . W.workspaces
relevantWorkspace = find idMatches <$> allWorkspaces
idMatches ws = W.tag ws == workspaceId
final = fmap (not . isInfixOf "Tabbed" . description . W.layout) <$>
relevantWorkspace
2016-10-26 15:19:49 -07:00
2021-08-05 17:32:25 -06:00
disableOnTabbed = ConditionalLayoutModifier DisableOnTabbedCondition
myMagnify = ModifiedLayout $ disableOnTabbed (Mag 1 (1.3, 1.3) On (AllWins 1))
2016-11-09 17:29:45 -08:00
2016-11-11 15:48:17 -08:00
-- Toggles
2021-09-13 03:14:55 -06:00
unmodifyLayout (ModifiedLayout _ x') = x'
unmodifyMuted (MutedModifiedLayout m) = unmodifyLayout m
data MutedModifiedLayout m l a =
MutedModifiedLayout (ModifiedLayout m l a) deriving (Read, Show)
instance (LayoutModifier m Window, LayoutClass l Window, Typeable m) =>
LayoutClass (MutedModifiedLayout m l) Window where
runLayout (W.Workspace i (MutedModifiedLayout l) ms) r =
fmap (fmap MutedModifiedLayout) `fmap` runLayout (W.Workspace i l ms) r
doLayout (MutedModifiedLayout l) r s =
fmap (fmap MutedModifiedLayout) `fmap` doLayout l r s
emptyLayout (MutedModifiedLayout l) r =
fmap (fmap MutedModifiedLayout) `fmap` emptyLayout l r
handleMessage (MutedModifiedLayout l) =
fmap (fmap MutedModifiedLayout) . handleMessage l
description (MutedModifiedLayout (ModifiedLayout m l)) = description l
selectLimit = myDmenu ["2", "3", "4"] >>= (setLimit . read)
data MyToggles
= LIMIT
| GAPS
| MAGICFOCUS
2021-08-03 13:03:23 -06:00
| MAGNIFY
2021-08-09 14:10:30 -06:00
| AVOIDSTRUTS
deriving (Read, Show, Eq, Typeable)
2016-11-11 15:48:17 -08:00
instance Transformer MyToggles Window where
2021-09-13 03:14:55 -06:00
transform LIMIT x k = k (MutedModifiedLayout $ limitSlice 2 x) unmodifyMuted
transform GAPS x k = k (MutedModifiedLayout $ smartSpacing 5 x) unmodifyMuted
transform MAGICFOCUS x k = k (MutedModifiedLayout $ magicFocus x) unmodifyMuted
transform MAGNIFY x k = k (MutedModifiedLayout $ myMagnify x) unmodifyMuted
transform AVOIDSTRUTS x k = k (MutedModifiedLayout $ avoidStruts x) unmodifyMuted
2016-11-11 15:48:17 -08:00
2021-08-09 14:10:30 -06:00
myToggles = [LIMIT, GAPS, MAGICFOCUS, MAGNIFY, AVOIDSTRUTS]
otherToggles = [NBFULL, NOBORDERS, MIRROR, SMARTBORDERS]
2021-08-09 14:10:30 -06:00
toggleHandlers =
[ (Toggle GAPS, toggleAll)
, (Toggle MAGNIFY, toggleAll)
, (Toggle AVOIDSTRUTS, toggleAll)
]
instance Eq (Toggle Window) where
(Toggle v) == v2 = Just v == fromToggle v2
fromToggle :: forall t. Typeable t => Toggle Window -> Maybe t
fromToggle (Toggle v) =
if typeOf v == typeRep (Proxy :: Proxy t) then
Just $ unsafeCoerce v
else
Nothing
2016-11-11 15:48:17 -08:00
currentWorkspace = W.workspace . W.current <$> gets windowset
isToggleActiveInCurrent t = currentWorkspace >>= isToggleActive t
followIfNoMagicFocus =
followOnlyIf $ maybe False not <$> isToggleActiveInCurrent MAGICFOCUS
togglesMap =
fmap M.fromList $ sequence $
map toggleTuple myToggles ++ map toggleTuple otherToggles
where
toggleTuple toggle = do
toggleString <- toggleToStringWithState toggle
return (toggleString, Toggle toggle)
toggleStateToString = maybe "N/A" (ifL "ON" "OFF")
toggleToStringWithState :: (Transformer t Window, Show t) => t -> X String
2016-11-21 17:42:55 -08:00
toggleToStringWithState toggle =
2016-11-30 17:19:19 -06:00
printf "%s (%s)" (show toggle) . toggleStateToString <$>
isToggleActiveInCurrent toggle
2016-11-11 15:48:17 -08:00
selectToggle =
togglesMap >>= DM.menuMapArgs "rofi" myDmenuArgs >>= flip whenJust runToggle
runToggle toggle =
let f = fromMaybe sendMessage $ lookup toggle toggleHandlers
in f toggle
toggleAll (Toggle toggle) = void $ runMaybeT $ do
active <- MaybeT $ isToggleActiveInCurrent toggle
lift $ setToggleActiveAll toggle (not active)
mapWorkspaces f = withWindowSet $ \ws -> do
let c = W.workspace . W.current $ ws
v = map W.workspace . W.visible $ ws
h = W.hidden ws
mapM f (c : v ++ h)
toggleInState t s ws = fmap (/= s) (isToggleActive t ws)
setToggleActive toggle active ws =
toggleInState toggle (Just active) ws >>=/
flip when (sendMessageWithNoRefresh (Toggle toggle) ws >> windows id)
-- Ambiguous type reference without signature
setToggleActiveCurrent :: (Transformer t Window) => t -> Bool -> X ()
2017-07-22 20:14:35 -07:00
setToggleActiveCurrent t a = void $ currentWorkspace >>= setToggleActive t a
setToggleActiveAll :: (Transformer t Window) => t -> Bool -> X ()
setToggleActiveAll t a = void $ mapWorkspaces (setToggleActive t a)
deactivateFull = setToggleActiveCurrent NBFULL False
toggleOr toggle toState action =
(currentWorkspace >>= setToggleActive toggle toState) >>= ((`when` action) . not)
deactivateFullOr = toggleOr NBFULL False
deactivateFullAnd action = sequence_ [deactivateFull, action]
andDeactivateFull action = sequence_ [action, deactivateFull]
2016-11-22 00:41:55 -06:00
goFullscreen = sendMessage $ JumpToLayout "Tabbed"
2016-11-11 15:48:17 -08:00
2016-11-09 17:29:45 -08:00
-- Layout setup
2016-10-26 15:19:49 -07:00
2017-01-04 16:35:51 -08:00
myTabConfig =
def { activeBorderColor = "#66cccc" }
2016-11-20 21:05:40 -08:00
rename newName = RN.renamed [RN.Replace newName]
layoutsStart layout = (layout, [Layout layout])
2016-11-20 21:05:40 -08:00
(|||!) (joined, layouts) newLayout =
(joined ||| newLayout, layouts ++ [Layout newLayout])
layoutInfo =
2021-08-05 16:41:19 -06:00
layoutsStart (rename "4 Columns" (multiCol [1, 1, 1] 2 0.0 (-0.5))) |||!
rename "3 Columns" (multiCol [1, 1] 2 0.01 (-0.5)) |||!
2021-08-03 14:01:39 -06:00
rename "Grid" Grid |||!
rename "Large Main" (Tall 1 (3 / 100) (3 / 4)) |||!
rename "2 Columns" (Tall 1 (3 / 100) (1 / 2)) |||!
2017-01-04 16:35:51 -08:00
Accordion |||! simpleCross |||! myTabbed
where
2021-08-21 13:48:33 -06:00
myTabbed = rename "Tabbed" $ tabbed shrinkText gothamTheme
2016-11-20 21:05:40 -08:00
layoutList = snd layoutInfo
layoutNames = [description layout | layout <- layoutList]
selectLayout = myDmenu layoutNames >>= (sendMessage . JumpToLayout)
myLayoutHook =
2021-09-13 03:14:55 -06:00
MutedModifiedLayout .
minimize .
boringAuto .
2021-08-09 14:10:30 -06:00
mkToggle1 AVOIDSTRUTS .
mkToggle1 MIRROR .
mkToggle1 LIMIT .
mkToggle1 GAPS .
mkToggle1 MAGICFOCUS .
mkToggle1 NBFULL .
2021-08-03 13:03:23 -06:00
mkToggle1 MAGNIFY .
mkToggle1 NOBORDERS .
mkToggle1 SMARTBORDERS .
lessBorders Screen $ fst layoutInfo
2016-11-09 17:29:45 -08:00
2016-10-26 15:19:49 -07:00
-- WindowBringer
2016-11-11 10:47:20 -08:00
myWindowBringerConfig =
def { menuCommand = "rofi"
, menuArgs = myDmenuArgs ++ ["-format", "i"]
, windowTitler = myDecorateName
}
2016-10-26 15:19:49 -07:00
classIfMatches window entry =
2016-11-26 09:53:47 -08:00
if' <$> runQuery (fst entry) window <*>
pure (Just $ snd entry) <*>
pure Nothing
getClassRaw w = fmap resClass $ withDisplay $ io . flip getClassHint w
getVirtualClass = flip findM virtualClasses . classIfMatches
getClass w = fromMaybe <$> getClassRaw w <*> getVirtualClass w
2021-08-05 16:41:19 -06:00
{-# NOINLINE desktopEntriesMap #-}
2019-06-23 21:24:30 -07:00
desktopEntriesMap :: MM.MultiMap String DesktopEntry
desktopEntriesMap =
2020-12-03 14:26:14 -08:00
unsafePerformIO $
2019-06-24 18:59:57 -07:00
indexDesktopEntriesByClassName <$> getDirectoryEntriesDefault
2019-06-23 21:24:30 -07:00
lookupIconFromClasses classes =
getFirst $ fold $ First . deIcon <$>
(classes >>= idAndLower >>= flip MM.lookup desktopEntriesMap)
2019-06-23 21:24:30 -07:00
where idAndLower value = [value, map toLower value]
xGetWindowProperty8 :: Atom -> Window -> X (Maybe [CChar])
xGetWindowProperty8 a w = withDisplay $ \dpy -> io $ getWindowProperty8 dpy a w
getEWMHClasses w = do
atom <- withDisplay $ \d -> io $ internAtom d "WM_CLASS" False
mValue <- fmap (UTF8.decode . map fromIntegral) <$> xGetWindowProperty8 atom w
pure $ filter (not . null) $ splitOn "\NUL" $ join $ maybeToList mValue
2021-07-04 01:33:58 -06:00
myDecorateName :: WindowSpace -> Window -> X String
myDecorateName ws w = do
name <- show <$> getName w
classes <- getEWMHClasses w
classTitle <- getClass w
2021-07-04 01:33:58 -06:00
workspaceToName <- getWorkspaceNames'
let iconName = fromMaybe (map toLower $ head classes) $
lookupIconFromClasses classes
2019-06-23 21:24:30 -07:00
entryString = printf "%-20s%-40s %+30s in %s \0icon\x1f%s"
classTitle (take 40 name) " "
(fromMaybe "" $ workspaceToName (W.tag ws)) iconName
2019-06-23 21:24:30 -07:00
return entryString
menuIndexArgs :: MonadIO m => String -> [String] -> [(String, a)] ->
m (Maybe a)
menuIndexArgs menuCmd args selectionPairs = do
selection <- menuFunction (map fst selectionPairs)
pure $ snd <$> (readMay selection >>= atMay selectionPairs)
where
menuFunction = DM.menuArgs menuCmd args
2017-03-28 17:57:25 -07:00
-- This needs access to X in order to unminimize, which means that it can't be
2016-11-21 23:26:52 -08:00
-- done with the existing window bringer interface
2019-06-23 21:24:30 -07:00
myWindowAct c@WindowBringerConfig {menuCommand = cmd, menuArgs = args}
filterVisible action = do
2017-08-24 12:07:47 -07:00
visible <- visibleWindows
currentlyFullscreen <- isToggleActiveInCurrent NBFULL
2021-08-05 16:41:19 -06:00
let actualConfig
| fromMaybe False currentlyFullscreen = c
| filterVisible = c { windowFilter = return . not . flip elem visible }
2021-08-05 16:41:19 -06:00
| otherwise = c
ws <- M.toList <$> windowMap' actualConfig
selection <- menuIndexArgs cmd args ws
2017-08-24 12:07:47 -07:00
whenJust selection action
doBringWindow window =
maximizeWindow window >> windows (W.focusWindow window . bringWindow window)
myWindowAction filterVisible =
andDeactivateFull . maybeUnminimizeAfter . myWindowAct myWindowBringerConfig filterVisible
myGoToWindow =
myWindowAction False $ windows . greedyFocusWindow
2021-08-05 16:41:19 -06:00
myBringWindow = myWindowAction True doBringWindow
myReplaceWindow =
swapMinimizeStateAfter $
2021-08-05 16:41:19 -06:00
myWindowAct myWindowBringerConfig True $ windows . swapFocusedWith
2016-11-09 17:29:45 -08:00
-- Workspace Names for EWMH
setWorkspaceNames :: X ()
setWorkspaceNames = withWindowSet $ \s -> withDisplay $ \dpy -> do
sort' <- getSortByIndex
let ws = sort' $ W.workspaces s
tagNames = map W.tag ws
2017-09-20 16:28:26 -07:00
getName tag = maybe "" (" " ++) <$> getWorkspaceName tag
getFullName :: String -> X String
getFullName tag = printf "%s%s" tag <$> getName tag
names <- mapM getFullName tagNames
r <- asks theRoot
a <- getAtom "_NET_DESKTOP_FULL_NAMES"
c <- getAtom "UTF8_STRING"
let names' = map fromIntegral $ concatMap ((++[0]) . UTF8String.encode) names
io $ changeProperty8 dpy r a c propModeReplace names'
-- Toggleable fade
newtype ToggleFade a =
ToggleFade { fadesMap :: M.Map a Bool }
2016-11-25 17:58:48 -08:00
deriving (Typeable, Read, Show)
instance (Typeable a, Read a, Show a, Ord a) =>
ExtensionClass (ToggleFade a) where
2016-11-25 17:58:48 -08:00
initialValue = ToggleFade M.empty
extensionType = PersistentExtension
fadeEnabledFor query =
M.findWithDefault True <$> query <*> liftX (fadesMap <$> XS.get)
fadeEnabledForWindow = fadeEnabledFor ask
fadeEnabledForWorkspace = fadeEnabledFor getWindowWorkspace
fadeEnabledForScreen = fadeEnabledFor getWindowScreen
2016-11-29 20:19:48 -08:00
getScreens = withWindowSet $ return . W.screens
getWindowWorkspace' = W.findTag <$> ask <*> liftX (withWindowSet return)
getWindowWorkspace = flip fromMaybe <$> getWindowWorkspace' <*> pure "1"
getWorkspaceToScreen =
M.fromList . mapP' (W.tag . W.workspace) W.screen <$> getScreens
2016-11-29 20:19:48 -08:00
getWindowScreen = M.lookup <$> getWindowWorkspace <*> liftX getWorkspaceToScreen
getCurrentScreen = join (withFocusedD Nothing (runQuery getWindowScreen))
2016-11-25 17:58:48 -08:00
fadeCondition =
isUnfocused <&&> fadeEnabledForWindow <&&>
fadeEnabledForWorkspace <&&> fadeEnabledForScreen
toggleFadeInactiveLogHook = fadeOutLogHook . fadeIf fadeCondition
2016-11-25 17:58:48 -08:00
toggleFadingForActiveWindow = withWindowSet $
maybe (return ()) toggleFading . W.peek
2016-11-25 17:58:48 -08:00
toggleFadingForActiveWorkspace =
withWindowSet $ \ws -> toggleFading $ W.currentTag ws
toggleFadingForActiveScreen = getCurrentScreen >>= toggleFading
toggleFading w = setFading' $ toggleInMap w
setFading w f = setFading' $ M.insert w f
setFading' f =
2021-08-05 16:41:19 -06:00
XS.get >>= XS.put . (ToggleFade . f . fadesMap)
2016-11-09 17:29:45 -08:00
-- Minimize not in class
2016-11-24 15:21:47 -08:00
restoreFocus action =
withFocused $ \orig -> action >> windows (W.focusWindow orig)
getCurrentWS = W.stack . W.workspace . W.current
2016-11-24 15:21:47 -08:00
withWorkspace f = withWindowSet $ \ws -> maybe (return ()) f (getCurrentWS ws)
currentWS = withWindowSet $ return . getCurrentWS
workspaceWindows = maybe [] W.integrate <$> currentWS
getMinMaxWindows =
partition <$> (flip elem <$> minimizedWindows) <*> workspaceWindows
maximizedWindows = fmap snd getMinMaxWindows
maximizedOtherClass =
intersect <$> maximizedWindows <*>
(currentWS >>= maybe (return []) windowsWithUnfocusedClass)
minimizedSameClass =
intersect <$> minimizedWindows <*>
(currentWS >>= maybe (return []) windowsWithFocusedClass)
getClassMatchesWindow w = (==) <$> getClass w
getClassMatchesCurrent = join $ withFocusedD (`seq` False) getClassMatchesWindow
minimizeOtherClassesInWorkspace =
actOnWindowsInWorkspace minimizeWindow windowsWithUnfocusedClass
maximizeSameClassesInWorkspace =
actOnWindowsInWorkspace maybeUnminimize windowsWithFocusedClass
-- Type annotation is needed to resolve ambiguity
actOnWindowsInWorkspace :: (Window -> X ())
-> (W.Stack Window -> X [Window])
-> X ()
actOnWindowsInWorkspace windowAction getWindowsAction = restoreFocus $
withWorkspace (getWindowsAction >=> mapM_ windowAction)
-- XXX: The idea behind this was that the normal fullscreen can be annoying if a
-- new window opens, but this behavior is even more annoying than that, so
-- nevermind
2017-04-14 19:37:30 -07:00
goFullscreenDWIM =
withWorkspace $ \ws -> do
wins <- windowsWithFocusedClass ws
if length wins > 1
then goFullscreen
else minimizeOtherClassesInWorkspace
windowsWithUnfocusedClass ws = windowsWithOtherClasses (W.focus ws) ws
windowsWithFocusedClass ws = windowsWithSameClass (W.focus ws) ws
windowsWithOtherClasses = windowsMatchingClassPredicate (/=)
windowsWithSameClass = windowsMatchingClassPredicate (==)
windowsMatchingClassPredicate predicate window workspace =
windowsSatisfyingPredicate workspace $ do
windowClass <- getClass window
return $ predicate windowClass
windowsSatisfyingPredicate workspace getPredicate = do
predicate <- getPredicate
2021-08-05 16:41:19 -06:00
filterM (fmap predicate . getClass) (W.integrate workspace)
getMatchingUnmatching =
partition <$> ((. snd) <$> getClassMatchesCurrent) <*> getWindowClassPairs
2021-08-05 16:41:19 -06:00
getWindowClassPairs = mapM windowToClassPair =<< workspaceWindows
windowToClassPair w = (,) w <$> getClass w
2022-03-25 14:13:26 -07:00
windowIsMinimized w = elem w <$> XS.gets minimizedStack
maybeUnminimize w = windowIsMinimized w >>= flip when (maximizeWindow w)
maybeUnminimizeFocused = withFocused maybeUnminimize
maybeUnminimizeAfter = (>> maybeUnminimizeFocused)
maybeUnminimizeClassAfter = (>> maximizeSameClassesInWorkspace)
2016-11-26 18:04:48 -08:00
sameClassOnly action =
action >> minimizeOtherClassesInWorkspace >> maximizeSameClassesInWorkspace
2017-03-10 16:06:16 -08:00
restoreAll = mapM_ maximizeWindow
restoreAllMinimized = minimizedWindows >>= restoreAll
2021-08-05 16:41:19 -06:00
restoreOrMinimizeOtherClasses = maximizedOtherClass >>=
ifL restoreAllMinimized minimizeOtherClassesInWorkspace . null
2016-11-26 18:04:48 -08:00
2017-03-10 16:06:16 -08:00
restoreThisClassOrMinimizeOtherClasses = minimizedSameClass >>= \ws ->
if' (null ws) minimizeOtherClassesInWorkspace $ restoreAll ws
2021-08-05 16:41:19 -06:00
getClassPair w = (, w) <$> getClass w
2016-11-26 18:04:48 -08:00
windowClassPairs = withWindowSet $ mapM getClassPair . W.allWindows
classToWindowMap = MM.fromList <$> windowClassPairs
allClasses = sort . MM.keys <$> classToWindowMap
thisClass = withWindowSet $ sequence . (getClass <$.> W.peek)
nextClass = do
classes <- allClasses
current <- thisClass
2017-04-12 18:00:01 -07:00
let index = join $ elemIndex <$> current <$$> classes
2016-11-26 18:04:48 -08:00
return $ fmap (\i -> cycle classes !! (i + 1)) index
classWindow c = do
m <- classToWindowMap
2021-08-05 16:41:19 -06:00
return (listToMaybe . flip MM.lookup m =<< c)
2016-11-26 18:04:48 -08:00
nextClassWindow = nextClass >>= classWindow
focusNextClass' =
2021-08-05 16:41:19 -06:00
(windows . maybe id greedyFocusWindow) =<< nextClassWindow
2016-11-26 18:04:48 -08:00
focusNextClass = sameClassOnly focusNextClass'
2021-08-05 16:41:19 -06:00
selectClass = myDmenu =<< allClasses
-- Gather windows of same class
2017-09-20 16:28:26 -07:00
allWindows = concat <$> mapWorkspaces (return . W.integrate' . W.stack)
windowsMatchingClass klass =
allWindows >>= filterM (((== klass) <$>) . getClass)
gatherClass klass = restoreFocus $
2017-10-13 22:10:00 -07:00
windowsMatchingClass klass >>= mapM_ doBringWindow
gatherThisClass = thisClass >>= flip whenJust gatherClass
2016-11-09 17:29:45 -08:00
-- Window switching
-- Use greedyView to switch to the correct workspace, and then focus on the
-- appropriate window within that workspace.
greedyFocusWindow w ws =
W.focusWindow w $
W.greedyView (fromMaybe (W.currentTag ws) $ W.findTag w ws) ws
2016-11-03 13:06:59 -07:00
shiftThenView i = W.greedyView i . W.shift i
greedyBringWindow w = greedyFocusWindow w . bringWindow w
shiftToEmptyAndView =
2021-08-05 16:41:19 -06:00
doTo Next emptyWS DWO.getSortByOrder (windows . shiftThenView)
2016-11-29 11:28:17 -08:00
setFocusedScreen :: ScreenId -> WindowSet -> WindowSet
setFocusedScreen to ws =
maybe ws (`setFocusedScreen'` ws) $ find ((to ==) . W.screen) (W.visible ws)
2016-11-29 11:28:17 -08:00
setFocusedScreen' to ws@W.StackSet
2016-11-29 11:28:17 -08:00
{ W.current = prevCurr
, W.visible = visible
} = ws { W.current = to
, W.visible = prevCurr:deleteBy screenEq to visible
2016-11-29 11:28:17 -08:00
}
where screenEq a b = W.screen a == W.screen b
nextScreen ws@W.StackSet { W.visible = visible } =
2016-11-29 11:28:17 -08:00
case visible of
next:_ -> setFocusedScreen (W.screen next) ws
_ -> ws
viewOtherScreen ws = W.greedyView ws . nextScreen
shiftThenViewOtherScreen ws w = viewOtherScreen ws . W.shiftWin ws w
2016-11-29 11:28:17 -08:00
shiftCurrentToWSOnOtherScreen ws s =
2021-08-05 16:41:19 -06:00
maybe s (flip (shiftThenViewOtherScreen ws) s) (W.peek s)
2016-11-29 11:28:17 -08:00
shiftToEmptyNextScreen =
2021-08-05 16:41:19 -06:00
doTo Next emptyWS DWO.getSortByOrder $ windows . shiftCurrentToWSOnOtherScreen
2016-11-29 11:28:17 -08:00
swapFocusedWith w ws = W.modify' (swapFocusedWith' w) (W.delete' w ws)
swapFocusedWith' w (W.Stack current ls rs) = W.Stack w ls (rs ++ [current])
swapMinimizeStateAfter action =
withFocused $ \originalWindow -> do
_ <- action
restoreFocus $ do
maybeUnminimizeFocused
withFocused $ \newWindow ->
when (newWindow /= originalWindow) $ minimizeWindow originalWindow
2016-11-09 17:29:45 -08:00
-- Named Scratchpads
2016-11-24 17:15:57 -06:00
nearFullFloat = customFloating $ W.RationalRect l t w h
where
h = 0.9
w = 0.9
t = 0.95 -h
l = 0.95 -w
scratchpads =
[ NS "element" elementCommand elementSelector nearFullFloat
, NS "gmail" gmailCommand gmailSelector nearFullFloat
, NS "htop" htopCommand (title =? "htop") nearFullFloat
, NS "messages" messagesCommand messagesSelector nearFullFloat
, NS "slack" slackCommand slackSelector nearFullFloat
, NS "spotify" spotifyCommand spotifySelector nearFullFloat
, NS "transmission" transmissionCommand transmissionSelector nearFullFloat
, NS "volume" volumeCommand volumeSelector nearFullFloat
]
myScratchPadManageHook = namedScratchpadManageHook scratchpads
-- We need this event hook because some scratchpad applications (Spotify) don't
-- actually properly set their class at startup.
myScratchPadEventHook
= dynamicPropertyChange "WM_CLASS" myScratchPadManageHook
<> dynamicPropertyChange "WM_NAME" myScratchPadManageHook
runScratchPadManageHookOnCurrent =
join (withFocusedD (Endo id) $ runQuery myScratchPadManageHook) >>= windows . appEndo
scratchPadIsDisplayed name = join $ withFocusedD False query
where
query = maybe (const $ return False) (runQuery . NS.query) scratchpadInfo
scratchpadInfo = find ((name ==) . NS.name) scratchpads
manageIfScratchPadIsDisplayed name =
scratchPadIsDisplayed name >>= (`when` runScratchPadManageHookOnCurrent)
2017-01-11 12:36:55 -08:00
-- TODO: This doesnt work well with minimized windows
doScratchpad name = do
maybeUnminimizeAfter $ deactivateFullAnd $ namedScratchpadAction scratchpads name
manageIfScratchPadIsDisplayed name
2016-11-09 17:29:45 -08:00
-- Raise or spawn
2016-11-25 20:22:08 -08:00
myRaiseNextMaybe =
((deactivateFullAnd . maybeUnminimizeAfter) .) .
2016-11-25 20:22:08 -08:00
raiseNextMaybeCustomFocus greedyFocusWindow
myBringNextMaybe =
((deactivateFullAnd . maybeUnminimizeAfter) .) .
raiseNextMaybeCustomFocus greedyBringWindow
bindBringAndRaise :: KeyMask
-> KeySym
-> X ()
-> Query Bool
-> [((KeyMask, KeySym), X ())]
bindBringAndRaise mask sym start query =
[ ((mask, sym), doRaiseNext)
2016-11-26 18:04:48 -08:00
, ((mask .|. controlMask, sym), myBringNextMaybe start query)
, ((mask .|. shiftMask, sym), doRaiseNext)
2016-11-26 18:04:48 -08:00
]
where doRaiseNext = myRaiseNextMaybe start query
bindBringAndRaiseMany :: [(KeyMask, KeySym, X (), Query Bool)]
-> [((KeyMask, KeySym), X ())]
bindBringAndRaiseMany = concatMap (\(a, b, c, d) -> bindBringAndRaise a b c d)
2016-11-09 17:29:45 -08:00
-- Screen shift
2016-11-24 17:15:57 -06:00
2016-12-25 15:32:09 -08:00
shiftToNextScreen ws =
case W.visible ws of
2016-12-25 15:32:09 -08:00
W.Screen i _ _:_ -> W.view (W.tag i) $ W.shift (W.tag i) ws
_ -> ws
shiftToNextScreenX = windows shiftToNextScreen
getNextScreen ws =
minimumBy compareScreen candidates
where currentId = W.screen $ W.current ws
otherScreens = W.visible ws
2017-05-30 14:48:52 -07:00
largerId = filter ((> currentId) . W.screen) otherScreens
compareScreen a b = compare (W.screen a) (W.screen b)
candidates =
case largerId of
[] -> W.current ws:otherScreens -- Ensure a value will be selected
_ -> largerId
2016-12-25 15:32:09 -08:00
goToNextScreen ws =
2017-05-30 14:48:52 -07:00
if screenEq nScreen currScreen then ws
else ws { W.current = nScreen
, W.visible = currScreen : trimmedVisible
}
where
currScreen = W.current ws
2017-05-30 14:48:52 -07:00
nScreen = getNextScreen ws
screenEq a b = W.screen a == W.screen b
trimmedVisible =
2017-05-30 14:48:52 -07:00
filter (not . screenEq nScreen) $ W.visible ws
2016-12-25 15:32:09 -08:00
goToNextScreenX = windows goToNextScreen
2016-11-09 17:29:45 -08:00
-- Key bindings
2021-08-02 05:18:07 -06:00
volumeUp = spawn "set_volume --unmute --change-volume +5"
volumeDown = spawn "set_volume --unmute --change-volume -5"
mute = spawn "set_volume --toggle-mute"
2017-07-25 01:23:10 -07:00
shiftToEmptyOnScreen direction =
followingWindow (windowToScreen direction True) >> shiftToEmptyAndView
directionalUp = xK_w
directionalDown = xK_s
directionalLeft = xK_a
directionalRight = xK_d
buildDirectionalBindings mask commandFn =
[ ((mask, directionalUp ), commandFn U)
, ((mask, directionalDown ), commandFn D)
, ((mask, directionalLeft ), commandFn L)
, ((mask, directionalRight), commandFn R)
]
myWindowGo direction = do
layoutName <- description . W.layout <$> currentWorkspace
2021-08-05 16:41:19 -06:00
if "Tabbed" `isInfixOf` layoutName
then
case direction of
2021-08-03 15:22:42 -06:00
D -> windows W.focusUp
L -> windows W.focusUp
R -> windows W.focusDown
U -> windows W.focusDown
else windowGo direction True
2017-03-10 15:06:20 -08:00
addKeys conf@XConfig { modMask = modm } =
-- Directional navigation
2021-08-05 16:41:19 -06:00
buildDirectionalBindings modm myWindowGo ++
buildDirectionalBindings
(modm .|. shiftMask) (`windowSwap` True) ++
buildDirectionalBindings
(modm .|. controlMask) (followingWindow . (`windowToScreen` True)) ++
buildDirectionalBindings hyper (`screenGo` True) ++
buildDirectionalBindings
(hyper .|. shiftMask) (followingWindow . (`screenSwap` True)) ++
buildDirectionalBindings
(hyper .|. controlMask) shiftToEmptyOnScreen ++
2016-12-28 19:41:57 -08:00
-- Specific program spawning
bindBringAndRaiseMany
2017-05-30 19:24:04 -07:00
[ (modalt, xK_c, spawn chromeCommand, chromeSelector)
] ++
-- ScratchPads
[ ((modalt, xK_e), doScratchpad "element")
, ((modalt, xK_g), doScratchpad "gmail")
, ((modalt, xK_h), doScratchpad "htop")
, ((modalt, xK_m), doScratchpad "messages")
, ((modalt, xK_k), doScratchpad "slack")
2017-05-19 13:23:35 -07:00
, ((modalt, xK_s), doScratchpad "spotify")
, ((modalt, xK_t), doScratchpad "transmission")
, ((modalt, xK_v), doScratchpad "volume")
-- Specific program spawning
2017-10-20 00:39:56 -07:00
, ((modm, xK_p), spawn "rofi -show drun -show-icons")
2016-09-19 11:07:03 -07:00
, ((modm .|. shiftMask, xK_p), spawn "rofi -show run")
-- Window manipulation
, ((modm, xK_g), myGoToWindow)
, ((modm, xK_b), myBringWindow)
, ((modm .|. shiftMask, xK_b), myReplaceWindow)
, ((modm .|. controlMask, xK_space), deactivateFullOr goFullscreen)
2016-10-03 14:57:58 -07:00
, ((modm, xK_m), withFocused minimizeWindow)
, ((modm .|. shiftMask, xK_m),
deactivateFullOr $ withLastMinimized maximizeWindowAndFocus)
, ((modm, xK_x), addHiddenWorkspace "NSP" >> windows (W.shift "NSP"))
, ((modalt, xK_space), deactivateFullOr restoreOrMinimizeOtherClasses)
, ((modalt, xK_Return), deactivateFullAnd restoreAllMinimized)
, ((hyper, xK_g), gatherThisClass)
2017-05-19 00:52:37 -07:00
-- Focus/Layout manipulation
2016-12-25 15:32:09 -08:00
, ((modm, xK_e), goToNextScreenX)
, ((modm, xK_slash), sendMessage $ Toggle MIRROR)
2017-04-14 19:21:54 -07:00
, ((modm, xK_backslash),
cycleWorkspaceOnCurrentScreen [xK_Super_L] xK_backslash xK_slash)
, ((modm, xK_space), deactivateFullOr $ sendMessage NextLayout)
2016-12-25 15:32:09 -08:00
, ((modm, xK_z), shiftToNextScreenX)
2016-11-29 11:28:17 -08:00
, ((modm .|. shiftMask, xK_z), shiftToEmptyNextScreen)
, ((modm .|. shiftMask, xK_h), shiftToEmptyAndView)
, ((hyper, xK_5), getWorkspaceDmenu >>= windows . SW.swapWithCurrent)
-- These need to be rebound to support boringWindows
, ((modm, xK_m), focusMaster)
2016-11-26 18:04:48 -08:00
, ((modm, xK_Tab), focusNextClass)
2021-08-05 16:41:19 -06:00
, ((hyper, xK_e), moveTo Next emptyWS)
2021-08-05 16:41:19 -06:00
-- Miscellaneous XMonad
2016-11-10 13:41:26 -08:00
2017-03-10 15:06:20 -08:00
, ((hyper, xK_1), toggleFadingForActiveWindow)
, ((hyper .|. shiftMask, xK_1), toggleFadingForActiveWorkspace)
, ((hyper .|. controlMask, xK_1), toggleFadingForActiveScreen)
, ((hyper, xK_t), selectToggle)
, ((modalt, xK_4), selectLimit)
2017-03-10 15:06:20 -08:00
, ((hyper, xK_3), addWorkspacePrompt def)
, ((modalt, xK_3), selectWorkspace def)
2017-03-10 15:06:20 -08:00
, ((hyper .|. mod1Mask, xK_3), removeWorkspace)
2017-09-09 19:40:13 -07:00
, ((hyper .|. mod1Mask, xK_r), renameWorkspace def)
-- Non-XMonad
2018-05-03 10:39:40 -07:00
, ((modm, xK_v), spawn "xclip -o | xdotool type --file -")
, ((hyper, xK_v), spawn "rofi_clipit.sh")
2017-03-10 15:06:20 -08:00
, ((hyper, xK_p), spawn "rofi-pass")
, ((hyper, xK_h), spawn "screenshot.sh")
, ((hyper, xK_c), spawn "shell_command.sh")
, ((hyper, xK_x), spawn "rofi_command.sh")
2017-03-10 15:06:20 -08:00
, ((hyper .|. shiftMask, xK_l), spawn "dm-tool lock")
, ((hyper, xK_l), selectLayout)
, ((hyper, xK_k), spawn "rofi_kill_process.sh")
2021-08-05 17:32:25 -06:00
, ((hyper .|. shiftMask, xK_k), spawn "rofi_kill_all.sh")
, ((hyper, xK_r), spawn "rofi-systemd")
2017-03-10 15:06:20 -08:00
, ((hyper, xK_9), spawn "start_synergy.sh")
2021-08-02 05:18:07 -06:00
, ((hyper, xK_slash), spawn "toggle_taffybar")
2017-03-28 14:55:42 -07:00
, ((hyper, xK_space), spawn "skippy-xd")
, ((hyper, xK_i), spawn "rofi_select_input.hs")
2021-08-02 05:18:07 -06:00
, ((hyper, xK_o), spawn "rofi_paswitch")
, ((modm, xK_apostrophe), spawn "load_default_map")
, ((modalt, xK_apostrophe), spawn "load_xkb_map")
-- Media keys
2016-10-05 02:20:35 -07:00
-- playerctl
2017-05-19 13:23:35 -07:00
, ((modm, xK_semicolon), spawn "playerctl play-pause")
, ((0, xF86XK_AudioPause), spawn "playerctl play-pause")
, ((0, xF86XK_AudioPlay), spawn "playerctl play-pause")
2017-05-19 13:23:35 -07:00
, ((modm, xK_l), spawn "playerctl next")
, ((0, xF86XK_AudioNext), spawn "playerctl next")
2017-05-19 13:23:35 -07:00
, ((modm, xK_j), spawn "playerctl previous")
, ((0, xF86XK_AudioPrev), spawn "playerctl previous")
-- Volume control
, ((0, xF86XK_AudioRaiseVolume), volumeUp)
, ((0, xF86XK_AudioLowerVolume), volumeDown)
, ((0, xF86XK_AudioMute), mute)
, ((modm, xK_i), volumeUp)
, ((modm, xK_k), volumeDown)
, ((modm, xK_u), mute)
2017-04-08 02:52:29 -07:00
, ((hyper .|. shiftMask, xK_q), spawn "toggle_mute_current_window.sh")
, ((hctrl, xK_q), spawn "toggle_mute_current_window.sh only")
2016-10-13 00:09:35 -07:00
2017-10-19 21:02:36 -07:00
, ((0, xF86XK_MonBrightnessUp), spawn "brightness.sh 5")
, ((0, xF86XK_MonBrightnessDown), spawn "brightness.sh -5")
] ++
-- Replace moving bindings
[((additionalMask .|. modm, key), windows $ function workspace)
| (workspace, key) <- zip (workspaces conf) [xK_1 .. xK_9]
, (function, additionalMask) <-
[ (W.greedyView, 0)
, (W.shift, shiftMask)
, (shiftThenView, controlMask)
]
]
2016-10-24 19:41:21 -07:00
where
modalt = modm .|. mod1Mask
2017-03-10 16:30:30 -08:00
hyper = mod3Mask
2017-03-10 15:06:20 -08:00
hctrl = hyper .|. controlMask
-- Local Variables:
-- flycheck-ghc-args: ("-Wno-missing-signatures")
2016-11-25 18:49:12 -08:00
-- haskell-indent-offset: 2
-- End: