701 lines
23 KiB
Haskell
Raw Normal View History

{-# LANGUAGE DeriveDataTypeable, TypeSynonymInstances,
MultiParamTypeClasses, ExistentialQuantification,
FlexibleInstances, FlexibleContexts #-}
module Main where
import qualified Control.Arrow as A
2016-11-24 18:33:49 -08:00
import Control.Monad
import Control.Monad.Trans.Maybe
import Data.Aeson
import qualified Data.ByteString.Lazy as B
2016-11-24 18:33:49 -08:00
import Data.List
import qualified Data.Map as M
2016-11-24 18:33:49 -08:00
import Data.Maybe
import qualified Data.MultiMap as MM
2016-11-24 18:33:49 -08:00
import Graphics.X11.ExtraTypes.XF86
import Network.HostName
2016-11-24 18:33:49 -08:00
import System.Directory
import System.FilePath.Posix
import System.Taffybar.Hooks.PagerHints
import Text.Printf
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)
2016-10-23 01:57:08 -07:00
import qualified XMonad.Actions.DynamicWorkspaceOrder as DWO
import XMonad.Actions.DynamicWorkspaces hiding (withWorkspace)
2016-11-24 18:33:49 -08:00
import XMonad.Actions.Minimize
import XMonad.Actions.UpdatePointer
2016-11-24 18:33:49 -08:00
import XMonad.Actions.WindowBringer
import XMonad.Actions.WindowGo
import XMonad.Actions.WorkspaceNames
import XMonad.Config ()
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.FadeInactive
import XMonad.Hooks.ManageDocks
2016-11-26 22:10:11 -08:00
import XMonad.Hooks.Minimize
2016-11-24 18:33:49 -08:00
import XMonad.Layout.Accordion
import XMonad.Layout.BoringWindows
import XMonad.Layout.LayoutCombinators
import XMonad.Layout.LayoutModifier
import XMonad.Layout.LimitWindows
import XMonad.Layout.MagicFocus
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
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
2016-11-24 15:26:43 -08:00
(NamedScratchpad(NS), nonFloating, namedScratchpadAction)
2016-11-24 18:33:49 -08:00
import XMonad.Util.NamedWindows (getName)
myGetWorkspaceNameFromTag getWSName tag =
printf "%s: %s " tag (fromMaybe "(Empty)" (getWSName tag))
main =
xmonad . docks $ def
{ modMask = mod4Mask
, terminal = "urxvt"
, manageHook = myManageHook <+> manageHook def
, layoutHook = myLayoutHook
2016-11-26 22:10:11 -08:00
, logHook =
updatePointer (0.5, 0.5) (0, 0) +++ toggleFadeInactiveLogHook 0.9 +++
2016-11-26 22:10:11 -08:00
ewmhWorkspaceNamesLogHook' myGetWorkspaceNameFromTag +++
(myGetWorkspaceNameFromTag <$> getWorkspaceNames' >>= pagerHintsLogHookCustom)
, handleEventHook = fullscreenEventHook +++
2016-11-26 22:10:11 -08:00
ewmhDesktopsEventHook +++ pagerHintsEventHook +++
followIfNoMagicFocus +++ minimizeEventHook
, startupHook = myStartup +++ ewmhWorkspaceNamesLogHook
, keys = customKeys (const []) addKeys
}
where
2016-10-26 13:23:44 -07:00
x +++ y = mappend y x
-- Utility functions
2016-11-29 15:46:51 -08:00
(<..>) a b = (fmap . fmap) a b
2016-11-25 18:39:27 -08:00
forkM :: Monad m => (i -> m a) -> (i -> m b) -> i -> m (a, b)
forkM a b input = do
resA <- a input
resB <- b input
return (resA, resB)
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
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
mapP = mapP' id
2016-11-29 20:19:48 -08:00
mapP' f f' = map (f A.&&& f')
2016-11-09 17:29:45 -08:00
-- Selectors
2016-10-26 15:19:49 -07:00
isHangoutsTitle = isPrefixOf "Google Hangouts"
chromeSelectorBase = className =? "Google-chrome"
2016-11-21 15:52:23 -08:00
chromeSelector = chromeSelectorBase <&&> fmap (not . isHangoutsTitle) title
2016-10-26 15:19:49 -07:00
spotifySelector = className =? "Spotify"
emacsSelector = className =? "Emacs"
transmissionSelector = fmap (isPrefixOf "Transmission") title
2016-11-21 15:52:23 -08:00
hangoutsSelector = chromeSelectorBase <&&> fmap isHangoutsTitle title
volumeSelector = className =? "Pavucontrol"
2016-10-26 15:19:49 -07:00
virtualClasses =
[ (hangoutsSelector, "Hangouts")
, (chromeSelector, "Chrome")
, (transmissionSelector, "Transmission")
]
2016-11-09 17:29:45 -08:00
2016-11-21 23:45:30 -06:00
-- Commands
hangoutsCommand = "start_hangouts.sh"
spotifyCommand = "spotify"
chromeCommand = "google-chrome-stable"
emacsCommand = "emacsclient -c"
htopCommnad = "urxvt -e htop"
transmissionCommand = "transmission-gtk"
volumeCommand = "pavucontrol"
2016-11-21 23:45:30 -06:00
-- Startup hook
tvScreenId :: ScreenId
2016-11-30 15:55:33 -08:00
tvScreenId = 1
disableTVFading = setFading (Just tvScreenId) False
hostNameToAction =
M.fromList [ ("imalison-arch", disableTVFading)
, ("imalison-uber-loaner", return ())
]
myStartup = do
spawn "systemctl --user start wm.target"
hostName <- io getHostName
M.findWithDefault (return ()) hostName hostNameToAction
2016-11-09 17:29:45 -08:00
-- Manage hook
2016-10-26 15:19:49 -07:00
myManageHook =
composeAll . concat $
[ [transmissionSelector --> doShift "5"]
-- Hangouts being on a separate workspace freezes chrome
-- , [ hangoutsSelector --> doShift "2"]
]
2016-11-09 17:29:45 -08:00
2016-11-11 15:48:17 -08:00
-- Toggles
2016-11-24 17:15:57 -06:00
2016-11-11 15:48:17 -08:00
unmodifyLayout (ModifiedLayout _ x') = x'
selectLimit =
DM.menuArgs "rofi" ["-dmenu", "-i"] ["2", "3", "4"] >>= (setLimit . read)
data MyToggles
= LIMIT
| GAPS
| MAGICFOCUS
deriving (Read, Show, Eq, Typeable)
2016-11-11 15:48:17 -08:00
instance Transformer MyToggles Window where
transform LIMIT x k = k (limitSlice 2 x) unmodifyLayout
transform GAPS x k = k (smartSpacing 5 x) unmodifyLayout
transform MAGICFOCUS x k = k (magicFocus x) unmodifyLayout
2016-11-11 15:48:17 -08:00
myToggles = [LIMIT, GAPS, MAGICFOCUS]
otherToggles = [NBFULL, MIRROR]
2016-11-11 15:48:17 -08:00
followIfNoMagicFocus =
followOnlyIf $ maybe False not <$> isToggleActive MAGICFOCUS
togglesMap =
fmap M.fromList $ sequence $
map toggleTuple myToggles ++ map toggleTuple otherToggles
where
toggleTuple toggle =
fmap (\str -> (str, Toggle toggle)) (toggleToStringWithState toggle)
toggleStateToString s =
case s of
Just True -> "ON"
Just False -> "OFF"
Nothing -> "N/A"
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 <$>
isToggleActive toggle
2016-11-11 15:48:17 -08:00
selectToggle =
togglesMap >>= DM.menuMapArgs "rofi" ["-dmenu", "-i"] >>=
flip whenJust sendMessage
toggleInState :: (Transformer t Window) => t -> Maybe Bool -> X Bool
toggleInState t s = fmap (/= s) (isToggleActive t)
2016-11-21 17:42:55 -08:00
setToggleActive' toggle active =
toggleInState toggle (Just active) >>=/
flip when (sendMessage $ Toggle toggle)
-- Ambiguous type reference without signature
setToggleActive :: (Transformer t Window) => t -> Bool -> X ()
setToggleActive = (void .) . setToggleActive'
deactivateFull = setToggleActive NBFULL False
toggleOr toggle toState action =
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 $ Toggle NBFULL
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
2016-11-20 21:05:40 -08:00
rename newName = RN.renamed [RN.Replace newName]
layoutsStart layout = (layout, [Layout layout])
(|||!) (joined, layouts) newLayout =
(joined ||| newLayout, layouts ++ [Layout newLayout])
layoutInfo =
layoutsStart (rename "Columns" $ multiCol [1, 1] 2 0.01 (-0.5)) |||!
rename "Large Main" (Tall 1 (3 / 100) (3 / 4)) |||!
rename "2 Columns" (Tall 1 (3 / 100) (1 / 2)) |||!
Accordion
2016-11-20 21:05:40 -08:00
layoutList = snd layoutInfo
layoutNames = [description layout | layout <- layoutList]
selectLayout =
DM.menuArgs "rofi" ["-dmenu", "-i"] layoutNames >>=
(sendMessage . JumpToLayout)
myLayoutHook =
avoidStruts . minimize . boringAuto . mkToggle1 MIRROR . mkToggle1 LIMIT .
mkToggle1 GAPS . mkToggle1 MAGICFOCUS . mkToggle1 NBFULL . workspaceNamesHook .
smartBorders . noBorders $ 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 =
WindowBringerConfig { menuCommand = "rofi"
2016-11-11 15:48:17 -08:00
, menuArgs = ["-dmenu", "-i"]
2016-11-20 12:13:49 -08:00
, 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
myDecorateName ws w = do
name <- show <$> getName w
classTitle <- getClass w
workspaceToName <- getWorkspaceNames
2016-10-27 04:07:45 -07:00
return $ printf "%-20s%-40s %+30s" classTitle (take 40 name)
"in " ++ workspaceToName (W.tag ws)
2016-11-24 15:26:43 -08:00
-- This needs access to X in order to unminimize, which means that I can't be
2016-11-21 23:26:52 -08:00
-- done with the existing window bringer interface
myBringWindow WindowBringerConfig { menuCommand = cmd
, menuArgs = args
, windowTitler = titler
} =
windowMap' titler >>= DM.menuMapArgs cmd args >>= flip whenJust action
where
action window =
sequence_
[ maximizeWindow window
, windows $ W.focusWindow window . bringWindow window
]
2016-11-09 17:29:45 -08:00
2016-10-26 15:19:49 -07:00
-- Dynamic Workspace Renaming
windowClassFontAwesomeFile =
fmap (</> ".lib/resources/window_class_to_fontawesome.json") getHomeDirectory
getClassRemap =
fmap (fromMaybe M.empty . decode) $
windowClassFontAwesomeFile >>= B.readFile
2016-11-25 18:56:07 -08:00
getClassRemapF = flip maybeRemap <$> getClassRemap
getWSClassNames' w = mapM getClass $ W.integrate' $ W.stack w
2016-11-25 20:22:08 -08:00
getWSClassNames w = io (fmap map getClassRemapF) <*> getWSClassNames' w
2016-11-25 18:56:07 -08:00
currentWSName ws = fromMaybe "" <$> (getWorkspaceNames' <*> pure (W.tag ws))
desiredWSName = (intercalate "|" <$>) . getWSClassNames
setWorkspaceNameToFocusedWindow workspace = do
currentName <- currentWSName workspace
newName <- desiredWSName workspace
when (currentName /= newName) $ setWorkspaceName (W.tag workspace) newName
setWorkspaceNames =
gets windowset >>= mapM_ setWorkspaceNameToFocusedWindow . W.workspaces
data WorkspaceNamesHook a = WorkspaceNamesHook deriving (Show, Read)
instance LayoutModifier WorkspaceNamesHook Window where
hook _ = setWorkspaceNames
workspaceNamesHook = ModifiedLayout WorkspaceNamesHook
2016-11-09 17:29:45 -08:00
-- 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"
2016-11-29 20:19:48 -08:00
getWorkspaceToScreen = M.fromList . mapP' (W.tag . W.workspace) W.screen <$> getScreens
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 =
fmap (ToggleFade . f . fadesMap) XS.get >>= XS.put
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
minimizedWindows = withMinimized return
getMinMaxWindows =
partition <$> (flip elem <$> minimizedWindows) <*> workspaceWindows
maximizedWindows = fmap snd getMinMaxWindows
maximizedOtherClass =
intersect <$> maximizedWindows <*>
(currentWS >>= maybe (return []) windowsWithUnfocusedClass)
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)
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
filterM (\w -> predicate <$> getClass w) (W.integrate workspace)
getMatchingUnmatching =
partition <$> ((. snd) <$> getClassMatchesCurrent) <*> getWindowClassPairs
getWindowClassPairs = join $ mapM windowToClassPair <$> workspaceWindows
windowToClassPair w = (,) w <$> getClass w
windowIsMinimized w = do
minimized <- XS.gets minimizedStack
return $ w `elem` minimized
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
2016-11-29 18:32:03 -08:00
restoreAllMinimized = void $ join $ mapM maximizeWindow <$> minimizedWindows
restoreOrMinimizeOtherClasses = null <$> maximizedOtherClass >>=
ifL restoreAllMinimized minimizeOtherClassesInWorkspace
2016-11-26 18:04:48 -08:00
getClassPair w = flip (,) w <$> getClass w
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
let index = join $ elemIndex <$> current <*> pure classes
return $ fmap (\i -> cycle classes !! (i + 1)) index
classWindow c = do
m <- classToWindowMap
return $ join $ listToMaybe <$> (flip MM.lookup m <$> c)
nextClassWindow = nextClass >>= classWindow
focusNextClass' = join $ windows . maybe id greedyFocusWindow <$> nextClassWindow
focusNextClass = sameClassOnly focusNextClass'
selectClass = join $ DM.menuArgs "rofi" ["-dmenu", "-i"] <$> allClasses
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 =
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
{ 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 } =
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 =
fromMaybe s (flip (shiftThenViewOtherScreen ws) s <$> W.peek s)
shiftToEmptyNextScreen =
doTo Next EmptyWS DWO.getSortByOrder $ windows . shiftCurrentToWSOnOtherScreen
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
scratchpads =
[ NS "htop" htopCommnad (title =? "htop") nonFloating
, NS "spotify" spotifyCommand spotifySelector nonFloating
, NS "hangouts" hangoutsCommand hangoutsSelector nonFloating
, NS "volume" volumeCommand volumeSelector nonFloating
]
doScratchpad = deactivateFullAnd . namedScratchpadAction scratchpads
2016-11-09 17:29:45 -08:00
-- Raise or spawn
2016-11-25 20:22:08 -08:00
myRaiseNextMaybe =
((deactivateFullAnd . maybeUnminimizeClassAfter) .) .
raiseNextMaybeCustomFocus greedyFocusWindow
myBringNextMaybe =
((deactivateFullAnd . maybeUnminimizeAfter) .) .
raiseNextMaybeCustomFocus greedyBringWindow
bindBringAndRaise :: KeyMask -> KeySym -> X () -> Query Bool -> [((KeyMask, KeySym), X ())]
bindBringAndRaise mask sym start query =
2016-11-26 18:04:48 -08:00
[ ((mask, sym), doRaiseNext)
, ((mask .|. controlMask, sym), myBringNextMaybe start query)
, ((mask .|. shiftMask, sym), doRaiseNext >> minimizeOtherClassesInWorkspace)
]
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
shiftToNextScreen = withWindowSet $ \ws ->
case W.visible ws of
W.Screen i _ _:_ -> windows $ W.view (W.tag i) . W.shift (W.tag i)
_ -> return ()
2016-11-09 17:29:45 -08:00
-- Key bindings
addKeys conf@XConfig {modMask = modm} =
[ ((modm, xK_p), spawn "rofi -show drun")
2016-09-19 11:07:03 -07:00
, ((modm .|. shiftMask, xK_p), spawn "rofi -show run")
2016-11-24 13:27:08 -08:00
, ((modm, xK_g), andDeactivateFull . maybeUnminimizeAfter $
actionMenu myWindowBringerConfig greedyFocusWindow)
2016-11-26 18:04:48 -08:00
, ((modm .|. shiftMask, xK_g), andDeactivateFull . sameClassOnly $
actionMenu myWindowBringerConfig greedyFocusWindow)
, ((modm, xK_b), andDeactivateFull $ myBringWindow myWindowBringerConfig)
2016-11-24 13:27:08 -08:00
, ((modm .|. shiftMask, xK_b),
swapMinimizeStateAfter $ actionMenu myWindowBringerConfig swapFocusedWith)
, ((modm .|. controlMask, xK_t), spawn
"systemctl --user restart taffybar.service")
2016-10-03 17:49:44 -07:00
, ((modm, xK_v), spawn "copyq paste")
2016-10-05 01:30:30 -07:00
, ((modm, xK_s), swapNextScreen)
2016-11-22 00:41:55 -06:00
, ((modm .|. controlMask, xK_space), goFullscreen)
, ((modm, xK_slash), sendMessage $ Toggle MIRROR)
2016-10-03 14:57:58 -07:00
, ((modm, xK_m), withFocused minimizeWindow)
, ((modm .|. shiftMask, xK_m),
deactivateFullOr $ withLastMinimized maximizeWindowAndFocus)
2016-10-24 17:17:35 -07:00
, ((modm, xK_backslash), toggleWS)
, ((modm, xK_space), deactivateFullOr $ sendMessage NextLayout)
, ((modm, xK_z), shiftToNextScreen)
2016-11-29 11:28:17 -08:00
, ((modm .|. shiftMask, xK_z), shiftToEmptyNextScreen)
, ((modm, xK_x), addHiddenWorkspace "NSP" >> (windows $ W.shift "NSP"))
, ((modm .|. shiftMask, xK_h), shiftToEmptyAndView)
-- These need to be rebound to support boringWindows
, ((modm, xK_j), focusDown)
, ((modm, xK_k), focusUp)
, ((modm, xK_m), focusMaster)
2016-11-26 18:04:48 -08:00
, ((modm, xK_Tab), focusNextClass)
, ((modm .|. controlMask, xK_s), spawn "split_out.sh")
2016-11-10 13:41:26 -08:00
2016-10-05 02:20:35 -07:00
-- Hyper bindings
, ((mod3Mask, xK_1), toggleFadingForActiveWindow)
, ((mod3Mask .|. shiftMask, xK_1), toggleFadingForActiveWorkspace)
, ((mod3Mask .|. controlMask, xK_1), toggleFadingForActiveScreen)
, ((mod3Mask, xK_e), moveTo Next EmptyWS)
2016-10-05 02:20:35 -07:00
, ((mod3Mask, xK_v), spawn "copyq_rofi.sh")
, ((mod3Mask, xK_p), spawn "rofi_password.sh")
2016-10-24 17:17:19 -07:00
, ((mod3Mask, xK_h), spawn "screenshot.sh")
, ((mod3Mask, xK_c), spawn "shell_command.sh")
, ((mod3Mask .|. shiftMask, xK_l), spawn "dm-tool lock")
, ((mod3Mask, xK_l), selectLayout)
, ((mod3Mask, xK_k), spawn "rofi_kill_process.sh")
2016-11-24 15:12:59 -08:00
, ((mod3Mask, xK_t), selectToggle)
, ((mod3Mask, xK_r), spawn "rofi_restart_service.sh")
2016-12-23 18:10:04 -08:00
, ((mod3Mask, xK_0), spawn "tvpower.js")
2016-10-05 02:20:35 -07:00
2016-10-27 14:48:13 -07:00
-- ModAlt bindings
2016-10-28 10:43:18 -07:00
, ((modalt, xK_w), spawn "rofi_wallpaper.sh")
2016-11-22 00:41:26 -08:00
, ((modalt, xK_z), spawn "split_out_chrome_tab.sh")
, ((modalt, xK_space), deactivateFullOr restoreOrMinimizeOtherClasses)
, ((modalt, xK_Return), deactivateFullAnd restoreAllMinimized)
, ((modalt, xK_4), selectLimit)
2016-10-27 14:48:13 -07:00
-- ScratchPads
, ((modalt, xK_m), doScratchpad "htop")
, ((modalt .|. controlMask, xK_s), doScratchpad "spotify")
, ((modalt .|. controlMask, xK_h), doScratchpad "hangouts")
, ((modalt .|. controlMask, xK_v), doScratchpad "volume")
, ((modalt, xK_h),
myRaiseNextMaybe (spawn hangoutsCommand) hangoutsSelector)
, ((modalt, xK_s),
myRaiseNextMaybe (spawn spotifyCommand) spotifySelector)
, ((modalt, xK_v),
myRaiseNextMaybe (spawn volumeCommand) volumeSelector)
2016-10-05 02:20:35 -07:00
-- playerctl
, ((mod3Mask, xK_f), spawn "playerctl play-pause")
, ((0, xF86XK_AudioPause), spawn "playerctl play-pause")
, ((0, xF86XK_AudioPlay), spawn "playerctl play-pause")
2016-10-05 02:20:35 -07:00
, ((mod3Mask, xK_d), spawn "playerctl next")
, ((0, xF86XK_AudioNext), spawn "playerctl next")
, ((mod3Mask, xK_a), spawn "playerctl previous")
, ((0, xF86XK_AudioPrev), spawn "playerctl previous")
-- volume control
, ((0, xF86XK_AudioRaiseVolume), spawn "pulseaudio-ctl up")
, ((0, xF86XK_AudioLowerVolume), spawn "pulseaudio-ctl down")
, ((0, xF86XK_AudioMute), spawn "pulseaudio-ctl mute")
, ((mod3Mask, xK_w), spawn "pulseaudio-ctl up")
, ((mod3Mask, xK_s), spawn "pulseaudio-ctl down")
2016-10-13 00:09:35 -07:00
] ++ bindBringAndRaiseMany
2016-10-13 00:09:35 -07:00
2016-11-21 23:45:30 -06:00
[ (modalt, xK_e, spawn emacsCommand, emacsSelector)
, (modalt, xK_c, spawn chromeCommand, chromeSelector)
-- , (modalt, xK_s, spawn spotifyCommand, spotifySelector)
-- , (modalt, xK_h, spawn hangoutsCommand, hangoutsSelector)
-- , (modalt, xK_v, spawn volumeCommand, volumeSelector)
2016-11-21 23:45:30 -06:00
, (modalt, xK_t, spawn transmissionCommand, transmissionSelector)
] ++
-- Replace original moving stuff around + greedy view 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
-- Local Variables:
-- flycheck-ghc-args: ("-Wno-missing-signatures")
2016-11-25 18:49:12 -08:00
-- haskell-indent-offset: 2
-- End: