2016-11-21 15:53:00 -08:00
|
|
|
|
{-# LANGUAGE DeriveDataTypeable, TypeSynonymInstances,
|
|
|
|
|
MultiParamTypeClasses, ExistentialQuantification,
|
2017-07-22 20:14:35 -07:00
|
|
|
|
FlexibleInstances, FlexibleContexts, ScopedTypeVariables #-}
|
2016-10-29 10:16:41 -07:00
|
|
|
|
module Main where
|
|
|
|
|
|
2019-06-24 15:35:40 -07:00
|
|
|
|
import Codec.Binary.UTF8.String as UTF8
|
2017-09-20 16:28:26 -07:00
|
|
|
|
import qualified Codec.Binary.UTF8.String as UTF8String (encode)
|
2016-11-29 22:47:44 -06:00
|
|
|
|
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
|
2016-10-21 22:01:51 -07:00
|
|
|
|
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
|
2017-03-31 22:36:15 -07:00
|
|
|
|
import Data.List.Split
|
2016-10-21 22:01:51 -07:00
|
|
|
|
import qualified Data.Map as M
|
2016-11-24 18:33:49 -08:00
|
|
|
|
import Data.Maybe
|
2017-07-17 12:32:08 -07:00
|
|
|
|
import Data.Monoid
|
2016-11-30 13:09:15 -06:00
|
|
|
|
import qualified Data.MultiMap as MM
|
2017-07-22 04:40:28 -07:00
|
|
|
|
import Data.Proxy
|
2017-09-20 16:28:26 -07:00
|
|
|
|
import Data.Tuple.Sequence (sequenceT)
|
2017-07-22 04:40:28 -07:00
|
|
|
|
import Data.Typeable
|
2019-06-24 15:35:40 -07:00
|
|
|
|
import Foreign.C.Types
|
2016-11-24 18:33:49 -08:00
|
|
|
|
import Graphics.X11.ExtraTypes.XF86
|
2016-11-30 13:09:15 -06:00
|
|
|
|
import Network.HostName
|
2018-06-14 15:57:27 -07:00
|
|
|
|
import PagerHints
|
2019-06-24 15:35:40 -07:00
|
|
|
|
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
|
2017-07-22 04:40:28 -07:00
|
|
|
|
import Unsafe.Coerce
|
2021-07-13 03:37:03 -06:00
|
|
|
|
import XMonad.Main (launch)
|
|
|
|
|
import XMonad.Core (getDirectories)
|
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
|
2017-07-17 12:30:42 -07:00
|
|
|
|
import qualified XMonad.Actions.SwapWorkspaces as SW
|
2016-12-23 21:06:27 -08:00
|
|
|
|
import XMonad.Actions.UpdatePointer
|
2016-11-24 18:33:49 -08:00
|
|
|
|
import XMonad.Actions.WindowBringer
|
|
|
|
|
import XMonad.Actions.WindowGo
|
2017-02-01 16:34:12 -08:00
|
|
|
|
import XMonad.Actions.WorkspaceNames
|
2016-11-24 18:33:49 -08:00
|
|
|
|
import XMonad.Config ()
|
|
|
|
|
import XMonad.Hooks.EwmhDesktops
|
|
|
|
|
import XMonad.Hooks.FadeInactive
|
|
|
|
|
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
|
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
|
2016-12-28 21:38:27 -08:00
|
|
|
|
import XMonad.Layout.Cross
|
2016-11-24 18:33:49 -08:00
|
|
|
|
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
|
2017-01-04 16:35:51 -08:00
|
|
|
|
import XMonad.Layout.Tabbed
|
2016-09-16 12:50:53 -07:00
|
|
|
|
import qualified XMonad.StackSet as W
|
2016-11-24 18:33:49 -08:00
|
|
|
|
import XMonad.Util.CustomKeys
|
2016-11-11 16:13:16 -08:00
|
|
|
|
import qualified XMonad.Util.Dmenu as DM
|
2016-10-22 17:17:25 -07:00
|
|
|
|
import qualified XMonad.Util.ExtensibleState as XS
|
2016-11-24 18:33:49 -08:00
|
|
|
|
import XMonad.Util.Minimize
|
|
|
|
|
import XMonad.Util.NamedScratchpad
|
|
|
|
|
import XMonad.Util.NamedWindows (getName)
|
2017-03-31 22:36:15 -07:00
|
|
|
|
import XMonad.Util.Run
|
2017-09-09 20:02:53 -07:00
|
|
|
|
import XMonad.Util.WorkspaceCompare
|
2016-09-14 16:56:37 -07:00
|
|
|
|
|
2017-07-17 12:29:50 -07:00
|
|
|
|
myConfig = def
|
2016-11-25 18:48:14 -08:00
|
|
|
|
{ modMask = mod4Mask
|
2021-07-12 18:12:20 -06:00
|
|
|
|
, terminal = "alacritty"
|
2016-12-01 16:23:30 -08:00
|
|
|
|
, manageHook = myManageHook <+> manageHook def
|
2016-11-25 18:48:14 -08:00
|
|
|
|
, layoutHook = myLayoutHook
|
2017-08-21 19:13:25 -07:00
|
|
|
|
, borderWidth = 0
|
2016-12-24 23:58:23 -08:00
|
|
|
|
, normalBorderColor = "#000000"
|
2017-07-29 00:37:54 -07:00
|
|
|
|
, focusedBorderColor = "#ffff00"
|
2016-11-26 22:10:11 -08:00
|
|
|
|
, logHook =
|
2017-01-31 04:14:07 -08:00
|
|
|
|
updatePointer (0.5, 0.5) (0, 0) +++
|
2017-09-10 13:16:18 -07:00
|
|
|
|
toggleFadeInactiveLogHook 0.9 +++ workspaceHistoryHook +++
|
|
|
|
|
setWorkspaceNames
|
2017-01-31 04:14:07 -08:00
|
|
|
|
, handleEventHook =
|
|
|
|
|
fullscreenEventHook +++ followIfNoMagicFocus +++ minimizeEventHook
|
|
|
|
|
, startupHook = myStartup
|
2016-11-25 18:48:14 -08:00
|
|
|
|
, keys = customKeys (const []) addKeys
|
|
|
|
|
}
|
|
|
|
|
where
|
2016-10-26 13:23:44 -07:00
|
|
|
|
x +++ y = mappend y x
|
2017-07-17 12:29:50 -07:00
|
|
|
|
|
2017-07-24 11:39:02 -07:00
|
|
|
|
myNavigation2DConfig = def { defaultTiledNavigation = centerNavigation }
|
|
|
|
|
|
2021-07-13 03:37:03 -06:00
|
|
|
|
main = do
|
|
|
|
|
dirs <- getDirectories
|
|
|
|
|
(flip launch dirs) . docks . pagerHints . ewmh . withNavigation2DConfig myNavigation2DConfig $ myConfig
|
|
|
|
|
|
2016-11-25 14:06:32 -08: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
|
|
|
|
|
|
2017-07-22 04:40:28 -07:00
|
|
|
|
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)
|
2016-11-25 14:06:32 -08:00
|
|
|
|
|
|
|
|
|
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
|
2016-11-25 14:06:32 -08:00
|
|
|
|
|
|
|
|
|
(>>=/) :: 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)
|
2016-11-25 18:38:32 -08:00
|
|
|
|
|
|
|
|
|
if' :: Bool -> a -> a -> a
|
|
|
|
|
if' True x _ = x
|
|
|
|
|
if' False _ y = y
|
|
|
|
|
|
2016-11-29 18:25:28 -08:00
|
|
|
|
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
|
|
|
|
|
|
2016-11-26 12:47:44 -08:00
|
|
|
|
toggleInMap' :: Ord k => Bool -> k -> M.Map k Bool -> M.Map k Bool
|
2016-11-25 18:41:16 -08:00
|
|
|
|
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
|
2016-11-25 18:41:16 -08:00
|
|
|
|
|
2016-11-26 12:47:44 -08:00
|
|
|
|
toggleInMap :: Ord k => k -> M.Map k Bool -> M.Map k Bool
|
2016-11-25 18:41:16 -08:00
|
|
|
|
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
|
|
|
|
|
2016-11-29 18:25:28 -08:00
|
|
|
|
withFocusedR f = withWindowSet (f . W.peek)
|
|
|
|
|
|
2016-11-29 22:47:44 -06:00
|
|
|
|
withFocusedD d f = maybe (return d) f <$> withWindowSet (return . W.peek)
|
2016-11-29 20:19:48 -08:00
|
|
|
|
|
2017-02-01 16:34:43 -08:00
|
|
|
|
withWorkspaceR f = withWindowSet $ f . W.workspace . W.current
|
|
|
|
|
|
2016-11-29 22:47:44 -06:00
|
|
|
|
mapP = mapP' id
|
2016-11-29 20:19:48 -08:00
|
|
|
|
|
2016-11-29 22:47:44 -06:00
|
|
|
|
mapP' f f' = map (f A.&&& f')
|
2017-02-01 16:34:43 -08:00
|
|
|
|
|
|
|
|
|
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)
|
2017-09-09 13:12:52 -07:00
|
|
|
|
res <- action
|
2017-05-30 14:48:52 -07:00
|
|
|
|
whenJust orig $ windows . W.focusWindow
|
2017-09-09 13:12:52 -07:00
|
|
|
|
return res
|
2017-07-17 12:30:42 -07:00
|
|
|
|
|
2019-06-23 21:24:30 -07:00
|
|
|
|
myDmenuArgs = ["-dmenu", "-i", "-show-icons"]
|
2017-07-20 14:42:36 -07:00
|
|
|
|
|
|
|
|
|
myDmenu = DM.menuArgs "rofi" myDmenuArgs
|
2017-07-17 12:30:42 -07:00
|
|
|
|
|
|
|
|
|
getWorkspaceDmenu = myDmenu (workspaces myConfig)
|
2016-11-09 17:29:45 -08:00
|
|
|
|
|
|
|
|
|
-- Selectors
|
|
|
|
|
|
2016-10-26 15:19:49 -07:00
|
|
|
|
isHangoutsTitle = isPrefixOf "Google Hangouts"
|
2017-05-30 19:24:04 -07:00
|
|
|
|
isGmailTitle t = isInfixOf "@gmail.com" t && isInfixOf "Gmail" t
|
2017-02-20 17:10:27 -08:00
|
|
|
|
isChromeClass = isInfixOf "chrome"
|
|
|
|
|
chromeSelectorBase = isChromeClass <$> className
|
2016-11-21 15:52:23 -08:00
|
|
|
|
|
2017-05-30 19:24:04 -07:00
|
|
|
|
chromeSelector =
|
|
|
|
|
chromeSelectorBase <&&>
|
|
|
|
|
(\t -> not $ any ($ t) [isHangoutsTitle, isGmailTitle]) <$> title
|
2016-10-26 15:19:49 -07:00
|
|
|
|
spotifySelector = className =? "Spotify"
|
|
|
|
|
emacsSelector = className =? "Emacs"
|
2016-10-31 17:40:33 -07:00
|
|
|
|
transmissionSelector = fmap (isPrefixOf "Transmission") title
|
2016-11-21 15:52:23 -08:00
|
|
|
|
hangoutsSelector = chromeSelectorBase <&&> fmap isHangoutsTitle title
|
2017-05-30 19:24:04 -07:00
|
|
|
|
gmailSelector = chromeSelectorBase <&&> fmap isGmailTitle title
|
2016-12-20 17:37:23 -08:00
|
|
|
|
volumeSelector = className =? "Pavucontrol"
|
2016-10-26 15:19:49 -07:00
|
|
|
|
|
2016-11-29 15:47:24 -08:00
|
|
|
|
virtualClasses =
|
|
|
|
|
[ (hangoutsSelector, "Hangouts")
|
2017-05-30 19:24:04 -07:00
|
|
|
|
, (gmailSelector, "Gmail")
|
2016-11-29 15:47:24 -08:00
|
|
|
|
, (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"
|
2017-05-30 19:24:04 -07:00
|
|
|
|
gmailCommand = "start_chrome.sh --new-window https://mail.google.com/mail/u/0/#inbox"
|
2016-11-21 23:45:30 -06:00
|
|
|
|
spotifyCommand = "spotify"
|
2017-07-07 16:49:36 -07:00
|
|
|
|
chromeCommand = "start_chrome.sh"
|
2016-11-21 23:45:30 -06:00
|
|
|
|
emacsCommand = "emacsclient -c"
|
2020-11-29 17:31:19 -08:00
|
|
|
|
htopCommand = "alacritty -e htop -t htop"
|
2016-11-21 23:45:30 -06:00
|
|
|
|
transmissionCommand = "transmission-gtk"
|
2016-12-20 17:37:23 -08:00
|
|
|
|
volumeCommand = "pavucontrol"
|
2016-11-21 23:45:30 -06:00
|
|
|
|
|
2016-11-10 18:05:50 -08:00
|
|
|
|
-- Startup hook
|
|
|
|
|
|
2016-11-30 13:09:15 -06:00
|
|
|
|
tvScreenId :: ScreenId
|
2016-11-30 15:55:33 -08:00
|
|
|
|
tvScreenId = 1
|
2016-11-30 13:09:15 -06:00
|
|
|
|
|
|
|
|
|
disableTVFading = setFading (Just tvScreenId) False
|
|
|
|
|
|
|
|
|
|
hostNameToAction =
|
2017-07-22 04:44:34 -07:00
|
|
|
|
M.fromList [ ("imalison-arch", disableTVFading >> setToggleActiveAll GAPS True)
|
2016-11-30 13:09:15 -06:00
|
|
|
|
, ("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
|
|
|
|
|
2017-07-17 12:32:08 -07:00
|
|
|
|
myManageHook = maybeReplaceTargetHook <+>
|
2017-03-10 15:09:28 -08:00
|
|
|
|
composeOne
|
2017-05-30 19:24:04 -07:00
|
|
|
|
[ isFullscreen -?> doFullFloat ]
|
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'
|
|
|
|
|
|
2016-11-25 18:48:14 -08:00
|
|
|
|
selectLimit =
|
2017-07-17 12:30:42 -07:00
|
|
|
|
myDmenu ["2", "3", "4"] >>= (setLimit . read)
|
2016-11-11 16:13:16 -08:00
|
|
|
|
|
2016-11-29 15:47:24 -08:00
|
|
|
|
data MyToggles
|
|
|
|
|
= LIMIT
|
|
|
|
|
| GAPS
|
|
|
|
|
| MAGICFOCUS
|
|
|
|
|
deriving (Read, Show, Eq, Typeable)
|
2016-11-11 15:48:17 -08:00
|
|
|
|
|
|
|
|
|
instance Transformer MyToggles Window where
|
2016-11-25 18:48:14 -08:00
|
|
|
|
transform LIMIT x k = k (limitSlice 2 x) unmodifyLayout
|
2017-07-22 20:14:35 -07:00
|
|
|
|
transform GAPS x k = k (smartSpacing 10 x) unmodifyLayout
|
2016-11-25 18:48:14 -08:00
|
|
|
|
transform MAGICFOCUS x k = k (magicFocus x) unmodifyLayout
|
2016-11-11 15:48:17 -08:00
|
|
|
|
|
2017-05-11 18:17:45 -07:00
|
|
|
|
myToggles = [LIMIT, GAPS, MAGICFOCUS]
|
2016-11-21 10:50:08 -08:00
|
|
|
|
otherToggles = [NBFULL, MIRROR]
|
2017-07-22 04:40:28 -07:00
|
|
|
|
toggleHandlers = [(Toggle GAPS, 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
|
|
|
|
|
2017-05-19 00:50:51 -07:00
|
|
|
|
currentWorkspace = W.workspace . W.current <$> gets windowset
|
|
|
|
|
isToggleActiveInCurrent t = currentWorkspace >>= isToggleActive t
|
|
|
|
|
|
2016-11-25 18:48:14 -08:00
|
|
|
|
followIfNoMagicFocus =
|
2017-05-19 00:50:51 -07:00
|
|
|
|
followOnlyIf $ maybe False not <$> isToggleActiveInCurrent MAGICFOCUS
|
2016-11-25 18:48:14 -08:00
|
|
|
|
|
2017-05-11 18:17:45 -07:00
|
|
|
|
togglesMap =
|
2016-11-25 18:48:14 -08:00
|
|
|
|
fmap M.fromList $ sequence $
|
2016-11-29 15:47:24 -08:00
|
|
|
|
map toggleTuple myToggles ++ map toggleTuple otherToggles
|
2016-11-25 18:48:14 -08:00
|
|
|
|
where
|
2017-07-22 04:40:28 -07:00
|
|
|
|
toggleTuple toggle = do
|
|
|
|
|
toggleString <- toggleToStringWithState toggle
|
|
|
|
|
return (toggleString, Toggle toggle)
|
2016-11-24 16:39:09 -08:00
|
|
|
|
|
2017-07-22 04:40:28 -07:00
|
|
|
|
toggleStateToString = maybe "N/A" (ifL "ON" "OFF")
|
2016-11-21 15:53:00 -08:00
|
|
|
|
|
|
|
|
|
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 <$>
|
2017-05-19 00:50:51 -07:00
|
|
|
|
isToggleActiveInCurrent toggle
|
2016-11-11 15:48:17 -08:00
|
|
|
|
|
2016-11-25 18:48:14 -08:00
|
|
|
|
selectToggle =
|
2017-07-22 04:40:28 -07:00
|
|
|
|
togglesMap >>= DM.menuMapArgs "rofi" myDmenuArgs >>= flip whenJust runToggle
|
|
|
|
|
|
|
|
|
|
runToggle toggle =
|
|
|
|
|
let f = fromMaybe sendMessage $ lookup toggle toggleHandlers
|
|
|
|
|
in f toggle
|
2016-11-21 15:53:00 -08:00
|
|
|
|
|
2017-07-22 04:40:28 -07:00
|
|
|
|
toggleAll (Toggle toggle) = void $ runMaybeT $ do
|
|
|
|
|
active <- MaybeT $ isToggleActiveInCurrent toggle
|
|
|
|
|
lift $ setToggleActiveAll toggle (not active)
|
2016-11-21 15:53:00 -08:00
|
|
|
|
|
2017-07-22 04:40:28 -07:00
|
|
|
|
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)
|
2016-11-21 15:53:00 -08:00
|
|
|
|
|
|
|
|
|
-- Ambiguous type reference without signature
|
2017-07-22 04:40:28 -07:00
|
|
|
|
setToggleActiveCurrent :: (Transformer t Window) => t -> Bool -> X ()
|
2017-07-22 20:14:35 -07:00
|
|
|
|
setToggleActiveCurrent t a = void $ currentWorkspace >>= setToggleActive t a
|
2017-07-22 04:40:28 -07:00
|
|
|
|
|
|
|
|
|
setToggleActiveAll :: (Transformer t Window) => t -> Bool -> X ()
|
|
|
|
|
setToggleActiveAll t a = void $ mapWorkspaces (setToggleActive t a)
|
2016-11-21 15:53:00 -08:00
|
|
|
|
|
2017-07-22 04:40:28 -07:00
|
|
|
|
deactivateFull = setToggleActiveCurrent NBFULL False
|
2016-11-21 17:25:56 -08:00
|
|
|
|
|
2016-11-25 18:48:14 -08:00
|
|
|
|
toggleOr toggle toState action =
|
2017-07-22 04:40:28 -07:00
|
|
|
|
(currentWorkspace >>= setToggleActive toggle toState) >>= ((`when` action) . not)
|
2016-11-21 15:53:00 -08:00
|
|
|
|
|
|
|
|
|
deactivateFullOr = toggleOr NBFULL False
|
2016-11-21 17:25:56 -08:00
|
|
|
|
deactivateFullAnd action = sequence_ [deactivateFull, action]
|
2016-11-21 20:06:34 -08:00
|
|
|
|
|
|
|
|
|
andDeactivateFull action = sequence_ [action, deactivateFull]
|
2016-11-22 00:41:55 -06:00
|
|
|
|
|
2019-06-23 21:24:30 -07:00
|
|
|
|
goFullscreen = sendMessage $ JumpToLayout "Tabbed Simplest"
|
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])
|
2019-06-02 22:48:29 -07:00
|
|
|
|
|
2016-11-20 21:05:40 -08:00
|
|
|
|
(|||!) (joined, layouts) newLayout =
|
|
|
|
|
(joined ||| newLayout, layouts ++ [Layout newLayout])
|
|
|
|
|
|
2016-11-25 18:48:14 -08:00
|
|
|
|
layoutInfo =
|
2019-06-02 22:48:29 -07: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)) |||!
|
2016-11-25 18:48:14 -08:00
|
|
|
|
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
|
|
|
|
|
myTabbed = tabbed shrinkText myTabConfig
|
2016-11-20 21:05:40 -08:00
|
|
|
|
|
|
|
|
|
layoutList = snd layoutInfo
|
|
|
|
|
|
|
|
|
|
layoutNames = [description layout | layout <- layoutList]
|
|
|
|
|
|
2017-07-20 14:42:36 -07:00
|
|
|
|
selectLayout = myDmenu layoutNames >>= (sendMessage . JumpToLayout)
|
2016-11-25 18:48:14 -08:00
|
|
|
|
|
|
|
|
|
myLayoutHook =
|
2017-04-09 13:23:04 -07:00
|
|
|
|
avoidStruts .
|
2019-06-10 08:13:19 -07:00
|
|
|
|
minimizeNoDescription .
|
2017-04-09 13:23:04 -07:00
|
|
|
|
boringAuto .
|
|
|
|
|
mkToggle1 MIRROR .
|
|
|
|
|
mkToggle1 LIMIT .
|
2017-05-11 18:17:45 -07:00
|
|
|
|
mkToggle1 GAPS .
|
2017-04-09 13:23:04 -07:00
|
|
|
|
mkToggle1 MAGICFOCUS .
|
|
|
|
|
mkToggle1 NBFULL .
|
2017-03-10 16:35:15 -08:00
|
|
|
|
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 =
|
2017-02-01 16:34:43 -08:00
|
|
|
|
def { menuCommand = "rofi"
|
2019-06-24 15:35:40 -07:00
|
|
|
|
, menuArgs = myDmenuArgs ++ ["-format", "i"]
|
2017-02-01 16:34:43 -08:00
|
|
|
|
, windowTitler = myDecorateName
|
|
|
|
|
}
|
2016-10-26 15:19:49 -07:00
|
|
|
|
|
2016-11-25 15:09:07 -08:00
|
|
|
|
classIfMatches window entry =
|
2016-11-26 09:53:47 -08:00
|
|
|
|
if' <$> runQuery (fst entry) window <*>
|
|
|
|
|
pure (Just $ snd entry) <*>
|
|
|
|
|
pure Nothing
|
2016-11-25 15:09:07 -08:00
|
|
|
|
|
|
|
|
|
getClassRaw w = fmap resClass $ withDisplay $ io . flip getClassHint w
|
|
|
|
|
|
|
|
|
|
getVirtualClass = flip findM virtualClasses . classIfMatches
|
|
|
|
|
|
|
|
|
|
getClass w = fromMaybe <$> getClassRaw w <*> getVirtualClass w
|
2016-10-21 21:58:14 -07:00
|
|
|
|
|
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 =
|
2019-06-24 15:35:40 -07:00
|
|
|
|
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]
|
|
|
|
|
|
2019-06-24 15:35:40 -07:00
|
|
|
|
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
|
2016-10-20 17:58:25 -07:00
|
|
|
|
myDecorateName ws w = do
|
|
|
|
|
name <- show <$> getName w
|
2019-06-24 15:35:40 -07:00
|
|
|
|
classes <- getEWMHClasses w
|
2016-10-21 21:58:14 -07:00
|
|
|
|
classTitle <- getClass w
|
2021-07-04 01:33:58 -06:00
|
|
|
|
workspaceToName <- getWorkspaceNames'
|
2019-06-24 15:35:40 -07:00
|
|
|
|
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"
|
2021-07-04 01:33:58 -06:00
|
|
|
|
classTitle (take 40 name) " " (fromMaybe "" $ workspaceToName (W.tag ws)) iconName
|
2019-06-23 21:24:30 -07:00
|
|
|
|
return entryString
|
2016-11-21 17:25:13 -08:00
|
|
|
|
|
2019-06-23 21:24:30 -07:00
|
|
|
|
data ChromeInfo = ChromeInfo
|
|
|
|
|
{ tabId :: Int
|
|
|
|
|
, tabUri :: String
|
|
|
|
|
, tabTitle :: String
|
|
|
|
|
} deriving (Eq, Show)
|
2017-03-31 22:36:15 -07:00
|
|
|
|
|
|
|
|
|
getChromeTabInfo = do
|
|
|
|
|
output <- runProcessWithInput "chromix-too" ["ls"] ""
|
|
|
|
|
return $ M.fromList $ map parseChromixLine $ lines output
|
|
|
|
|
where parseChromixLine line =
|
|
|
|
|
case splitOn " " line of
|
2017-05-30 14:48:52 -07:00
|
|
|
|
[] -> undefined
|
2017-03-31 22:36:15 -07:00
|
|
|
|
tid:uri:rest -> let ttl = concat rest in
|
|
|
|
|
(printf "%s - %s" tid ttl :: String,
|
|
|
|
|
ChromeInfo { tabId = read tid
|
|
|
|
|
, tabUri = uri
|
|
|
|
|
, tabTitle = ttl
|
|
|
|
|
})
|
2017-05-30 14:48:52 -07:00
|
|
|
|
[_] -> undefined
|
2017-03-31 22:36:15 -07:00
|
|
|
|
|
|
|
|
|
selectChromeTab WindowBringerConfig { menuCommand = cmd
|
|
|
|
|
, menuArgs = args
|
|
|
|
|
} =
|
|
|
|
|
liftIO getChromeTabInfo >>= void . DM.menuMapArgs cmd args
|
|
|
|
|
|
|
|
|
|
chromeTabAction doSplit action selected =
|
|
|
|
|
case selected of
|
|
|
|
|
Left wid -> action wid
|
|
|
|
|
Right ChromeInfo { tabId = tid } ->
|
|
|
|
|
liftIO $ do
|
|
|
|
|
let command = if doSplit then
|
2017-05-19 00:51:35 -07:00
|
|
|
|
"split_tab_by_id.sh %s"
|
2017-03-31 22:36:15 -07:00
|
|
|
|
else
|
2017-05-19 00:51:35 -07:00
|
|
|
|
"focus_tab_by_id.sh %s"
|
|
|
|
|
spawn $ printf command $ show tid
|
2017-03-31 22:36:15 -07:00
|
|
|
|
return ()
|
2017-03-28 17:57:25 -07:00
|
|
|
|
|
2019-06-24 15:35:40 -07:00
|
|
|
|
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
|
2018-06-25 19:36:40 -07:00
|
|
|
|
currentlyFullscreen <- isToggleActiveInCurrent NBFULL
|
|
|
|
|
let actualConfig =
|
|
|
|
|
if fromMaybe False currentlyFullscreen
|
|
|
|
|
then c
|
|
|
|
|
else
|
|
|
|
|
if filterVisible
|
|
|
|
|
then c {windowFilter = not . flip elem visible}
|
|
|
|
|
else c
|
2019-06-24 15:35:40 -07:00
|
|
|
|
ws <- M.toList <$> windowMap' actualConfig
|
|
|
|
|
selection <- menuIndexArgs cmd args ws
|
2017-08-24 12:07:47 -07:00
|
|
|
|
whenJust selection action
|
2017-02-01 16:34:43 -08:00
|
|
|
|
|
2017-03-31 22:36:15 -07:00
|
|
|
|
doBringWindow window =
|
|
|
|
|
maximizeWindow window >> windows (W.focusWindow window . bringWindow window)
|
2017-02-01 16:34:43 -08:00
|
|
|
|
|
2018-06-25 19:36:40 -07:00
|
|
|
|
myWindowAction filterVisible =
|
|
|
|
|
andDeactivateFull . maybeUnminimizeAfter . myWindowAct myWindowBringerConfig filterVisible
|
2017-03-31 22:36:15 -07:00
|
|
|
|
|
|
|
|
|
myGoToWindow =
|
2019-06-24 15:35:40 -07:00
|
|
|
|
myWindowAction False $ windows . greedyFocusWindow
|
2017-03-31 22:36:15 -07:00
|
|
|
|
|
2019-06-24 15:35:40 -07:00
|
|
|
|
myBringWindow = myWindowAction True $ doBringWindow
|
2017-03-31 22:36:15 -07:00
|
|
|
|
|
|
|
|
|
myReplaceWindow =
|
2017-04-09 13:23:04 -07:00
|
|
|
|
swapMinimizeStateAfter $
|
2019-06-24 15:35:40 -07:00
|
|
|
|
myWindowAct myWindowBringerConfig True $ (windows . swapFocusedWith)
|
2016-11-09 17:29:45 -08:00
|
|
|
|
|
2017-09-09 20:02:53 -07:00
|
|
|
|
-- Workspace Names for EWMH
|
|
|
|
|
|
2017-09-10 13:16:18 -07:00
|
|
|
|
setWorkspaceNames :: X ()
|
|
|
|
|
setWorkspaceNames = withWindowSet $ \s -> withDisplay $ \dpy -> do
|
2017-09-09 20:02:53 -07:00
|
|
|
|
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
|
2017-09-09 20:02:53 -07:00
|
|
|
|
getFullName :: String -> X String
|
|
|
|
|
getFullName tag = printf "%s%s" tag <$> getName tag
|
|
|
|
|
names <- mapM getFullName tagNames
|
|
|
|
|
r <- asks theRoot
|
2017-09-10 13:16:18 -07:00
|
|
|
|
a <- getAtom "_NET_DESKTOP_FULL_NAMES"
|
2017-09-09 20:02:53 -07:00
|
|
|
|
c <- getAtom "UTF8_STRING"
|
|
|
|
|
let names' = map fromIntegral $ concatMap ((++[0]) . UTF8String.encode) names
|
|
|
|
|
io $ changeProperty8 dpy r a c propModeReplace names'
|
|
|
|
|
|
2017-02-01 16:34:12 -08:00
|
|
|
|
|
2016-10-27 00:17:42 -07:00
|
|
|
|
-- Toggleable fade
|
|
|
|
|
|
2016-11-26 12:47:44 -08:00
|
|
|
|
newtype ToggleFade a =
|
|
|
|
|
ToggleFade { fadesMap :: M.Map a Bool }
|
2016-11-25 17:58:48 -08:00
|
|
|
|
deriving (Typeable, Read, Show)
|
2016-10-27 00:17:42 -07:00
|
|
|
|
|
2017-04-09 13:23:04 -07:00
|
|
|
|
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
|
|
|
|
|
|
2016-11-26 12:47:44 -08:00
|
|
|
|
fadeEnabledFor query =
|
|
|
|
|
M.findWithDefault True <$> query <*> liftX (fadesMap <$> XS.get)
|
|
|
|
|
|
|
|
|
|
fadeEnabledForWindow = fadeEnabledFor ask
|
|
|
|
|
fadeEnabledForWorkspace = fadeEnabledFor getWindowWorkspace
|
2016-11-30 13:09:15 -06:00
|
|
|
|
fadeEnabledForScreen = fadeEnabledFor getWindowScreen
|
2016-11-26 12:47:44 -08:00
|
|
|
|
|
2016-11-29 20:19:48 -08:00
|
|
|
|
getScreens = withWindowSet $ return . W.screens
|
2016-11-26 12:47:44 -08:00
|
|
|
|
getWindowWorkspace' = W.findTag <$> ask <*> liftX (withWindowSet return)
|
|
|
|
|
getWindowWorkspace = flip fromMaybe <$> getWindowWorkspace' <*> pure "1"
|
2017-04-09 13:23:04 -07:00
|
|
|
|
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
|
2016-11-30 13:09:15 -06:00
|
|
|
|
getCurrentScreen = join (withFocusedD Nothing (runQuery getWindowScreen))
|
2016-11-25 17:58:48 -08:00
|
|
|
|
|
2016-11-30 17:18:31 -06:00
|
|
|
|
fadeCondition =
|
|
|
|
|
isUnfocused <&&> fadeEnabledForWindow <&&>
|
|
|
|
|
fadeEnabledForWorkspace <&&> fadeEnabledForScreen
|
|
|
|
|
|
|
|
|
|
toggleFadeInactiveLogHook = fadeOutLogHook . fadeIf fadeCondition
|
2016-11-25 17:58:48 -08:00
|
|
|
|
|
|
|
|
|
toggleFadingForActiveWindow = withWindowSet $
|
2016-11-29 20:18:53 -08:00
|
|
|
|
maybe (return ()) toggleFading . W.peek
|
2016-11-25 17:58:48 -08:00
|
|
|
|
|
2016-11-26 12:47:44 -08:00
|
|
|
|
toggleFadingForActiveWorkspace =
|
2016-11-29 20:18:53 -08:00
|
|
|
|
withWindowSet $ \ws -> toggleFading $ W.currentTag ws
|
2016-11-26 12:47:44 -08:00
|
|
|
|
|
2016-11-30 13:09:15 -06:00
|
|
|
|
toggleFadingForActiveScreen = getCurrentScreen >>= toggleFading
|
|
|
|
|
|
2016-11-29 20:18:53 -08:00
|
|
|
|
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
|
|
|
|
|
2016-11-08 01:40:10 -08:00
|
|
|
|
-- Minimize not in class
|
|
|
|
|
|
2016-11-24 15:21:47 -08:00
|
|
|
|
restoreFocus action =
|
|
|
|
|
withFocused $ \orig -> action >> windows (W.focusWindow orig)
|
2016-11-10 15:23:37 -08:00
|
|
|
|
|
2016-11-11 15:48:47 -08:00
|
|
|
|
getCurrentWS = W.stack . W.workspace . W.current
|
|
|
|
|
|
2016-11-24 15:21:47 -08:00
|
|
|
|
withWorkspace f = withWindowSet $ \ws -> maybe (return ()) f (getCurrentWS ws)
|
2016-11-08 01:40:10 -08:00
|
|
|
|
|
2016-11-29 18:25:28 -08:00
|
|
|
|
currentWS = withWindowSet $ return . getCurrentWS
|
|
|
|
|
|
2016-11-29 22:47:44 -06:00
|
|
|
|
workspaceWindows = maybe [] W.integrate <$> currentWS
|
2016-11-29 18:25:28 -08:00
|
|
|
|
|
|
|
|
|
getMinMaxWindows =
|
|
|
|
|
partition <$> (flip elem <$> minimizedWindows) <*> workspaceWindows
|
|
|
|
|
|
|
|
|
|
maximizedWindows = fmap snd getMinMaxWindows
|
|
|
|
|
|
|
|
|
|
maximizedOtherClass =
|
|
|
|
|
intersect <$> maximizedWindows <*>
|
|
|
|
|
(currentWS >>= maybe (return []) windowsWithUnfocusedClass)
|
|
|
|
|
|
2016-12-28 21:38:48 -08:00
|
|
|
|
minimizedSameClass =
|
|
|
|
|
intersect <$> minimizedWindows <*>
|
|
|
|
|
(currentWS >>= maybe (return []) windowsWithFocusedClass)
|
|
|
|
|
|
2016-11-29 18:25:28 -08:00
|
|
|
|
getClassMatchesWindow w = (==) <$> getClass w
|
|
|
|
|
getClassMatchesCurrent = join $ withFocusedD (`seq` False) getClassMatchesWindow
|
|
|
|
|
|
2016-11-11 12:06:03 -08:00
|
|
|
|
minimizeOtherClassesInWorkspace =
|
2016-11-29 15:47:24 -08:00
|
|
|
|
actOnWindowsInWorkspace minimizeWindow windowsWithUnfocusedClass
|
2016-11-11 12:06:03 -08:00
|
|
|
|
maximizeSameClassesInWorkspace =
|
2016-11-29 15:47:24 -08:00
|
|
|
|
actOnWindowsInWorkspace maybeUnminimize windowsWithFocusedClass
|
2016-11-11 12:06:03 -08:00
|
|
|
|
|
|
|
|
|
-- Type annotation is needed to resolve ambiguity
|
2016-11-26 09:54:12 -08:00
|
|
|
|
actOnWindowsInWorkspace :: (Window -> X ())
|
|
|
|
|
-> (W.Stack Window -> X [Window])
|
|
|
|
|
-> X ()
|
2016-11-11 12:06:03 -08:00
|
|
|
|
actOnWindowsInWorkspace windowAction getWindowsAction = restoreFocus $
|
|
|
|
|
withWorkspace (getWindowsAction >=> mapM_ windowAction)
|
|
|
|
|
|
2017-04-14 21:08:11 -07:00
|
|
|
|
-- 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
|
|
|
|
|
|
2016-11-11 12:06:03 -08:00
|
|
|
|
windowsWithUnfocusedClass ws = windowsWithOtherClasses (W.focus ws) ws
|
|
|
|
|
windowsWithFocusedClass ws = windowsWithSameClass (W.focus ws) ws
|
2016-11-29 15:47:24 -08:00
|
|
|
|
windowsWithOtherClasses = windowsMatchingClassPredicate (/=)
|
|
|
|
|
windowsWithSameClass = windowsMatchingClassPredicate (==)
|
2016-11-11 12:06:03 -08:00
|
|
|
|
|
2016-11-29 15:47:24 -08:00
|
|
|
|
windowsMatchingClassPredicate predicate window workspace =
|
|
|
|
|
windowsSatisfyingPredicate workspace $ do
|
|
|
|
|
windowClass <- getClass window
|
|
|
|
|
return $ predicate windowClass
|
2016-11-11 12:06:03 -08:00
|
|
|
|
|
|
|
|
|
windowsSatisfyingPredicate workspace getPredicate = do
|
2016-11-29 15:47:24 -08:00
|
|
|
|
predicate <- getPredicate
|
|
|
|
|
filterM (\w -> predicate <$> getClass w) (W.integrate workspace)
|
2016-11-08 01:40:10 -08:00
|
|
|
|
|
2016-11-29 18:25:28 -08:00
|
|
|
|
getMatchingUnmatching =
|
|
|
|
|
partition <$> ((. snd) <$> getClassMatchesCurrent) <*> getWindowClassPairs
|
|
|
|
|
|
2016-11-29 22:47:44 -06:00
|
|
|
|
getWindowClassPairs = join $ mapM windowToClassPair <$> workspaceWindows
|
2016-11-29 18:25:28 -08:00
|
|
|
|
|
|
|
|
|
windowToClassPair w = (,) w <$> getClass w
|
|
|
|
|
|
2016-11-10 18:05:50 -08:00
|
|
|
|
windowIsMinimized w = do
|
|
|
|
|
minimized <- XS.gets minimizedStack
|
|
|
|
|
return $ w `elem` minimized
|
|
|
|
|
|
2016-11-11 12:06:03 -08:00
|
|
|
|
maybeUnminimize w = windowIsMinimized w >>= flip when (maximizeWindow w)
|
|
|
|
|
|
|
|
|
|
maybeUnminimizeFocused = withFocused maybeUnminimize
|
2016-11-10 18:05:50 -08:00
|
|
|
|
|
2016-11-11 12:13:31 -08:00
|
|
|
|
maybeUnminimizeAfter = (>> maybeUnminimizeFocused)
|
|
|
|
|
|
|
|
|
|
maybeUnminimizeClassAfter = (>> maximizeSameClassesInWorkspace)
|
2016-11-10 21:08:45 -08:00
|
|
|
|
|
2016-11-26 18:04:48 -08:00
|
|
|
|
sameClassOnly action =
|
|
|
|
|
action >> minimizeOtherClassesInWorkspace >> maximizeSameClassesInWorkspace
|
|
|
|
|
|
2017-03-10 16:06:16 -08:00
|
|
|
|
restoreAll = mapM_ maximizeWindow
|
2016-12-28 21:38:48 -08:00
|
|
|
|
|
|
|
|
|
restoreAllMinimized = minimizedWindows >>= restoreAll
|
2016-11-10 15:23:37 -08:00
|
|
|
|
|
2016-11-29 18:25:28 -08:00
|
|
|
|
restoreOrMinimizeOtherClasses = null <$> maximizedOtherClass >>=
|
|
|
|
|
ifL restoreAllMinimized minimizeOtherClassesInWorkspace
|
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
|
2016-12-28 21:38:48 -08:00
|
|
|
|
|
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
|
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
|
|
|
|
|
return $ join $ listToMaybe <$> (flip MM.lookup m <$> c)
|
|
|
|
|
|
|
|
|
|
nextClassWindow = nextClass >>= classWindow
|
|
|
|
|
|
2017-04-09 13:23:04 -07:00
|
|
|
|
focusNextClass' =
|
|
|
|
|
join $ windows . maybe id greedyFocusWindow <$> nextClassWindow
|
2016-11-26 18:04:48 -08:00
|
|
|
|
focusNextClass = sameClassOnly focusNextClass'
|
|
|
|
|
|
2017-07-20 14:42:36 -07:00
|
|
|
|
selectClass = join $ myDmenu <$> allClasses
|
2016-11-09 17:29:45 -08:00
|
|
|
|
|
2017-07-17 12:32:08 -07:00
|
|
|
|
-- Chrome auto minimization
|
|
|
|
|
|
|
|
|
|
data ReplaceOnNew
|
|
|
|
|
= NoTarget
|
|
|
|
|
| DontTarget
|
|
|
|
|
| Target Window
|
|
|
|
|
deriving (Typeable, Read, Show)
|
|
|
|
|
|
|
|
|
|
instance ExtensionClass ReplaceOnNew where
|
|
|
|
|
initialValue = NoTarget
|
|
|
|
|
extensionType = PersistentExtension
|
|
|
|
|
|
|
|
|
|
mapWindows f = W.mapWorkspace workspaceHelper
|
|
|
|
|
where
|
|
|
|
|
stackHelper stack = W.Stack
|
|
|
|
|
{ W.focus = f $ W.focus stack
|
|
|
|
|
, W.up = map f $ W.up stack
|
|
|
|
|
, W.down = map f $ W.down stack
|
|
|
|
|
}
|
|
|
|
|
workspaceHelper ws@W.Workspace {W.stack = stack} =
|
|
|
|
|
ws { W.stack = stackHelper <$> stack }
|
|
|
|
|
|
|
|
|
|
swapWindows a b =
|
|
|
|
|
mapWindows helper
|
|
|
|
|
where helper w
|
|
|
|
|
| w == a = b
|
|
|
|
|
| w == b = a
|
|
|
|
|
| otherwise = w
|
|
|
|
|
|
|
|
|
|
getTarget = do
|
|
|
|
|
t <- XS.get
|
|
|
|
|
case t of
|
|
|
|
|
Target w -> return $ Just w
|
|
|
|
|
DontTarget -> return Nothing
|
|
|
|
|
NoTarget -> return Nothing
|
|
|
|
|
|
|
|
|
|
maybeReplaceTarget :: Window -> X ()
|
|
|
|
|
maybeReplaceTarget window = do
|
|
|
|
|
t <- getTarget
|
|
|
|
|
-- We have an insertUp here to ensure the target isn't deleted
|
|
|
|
|
let modifyStackSet target = W.insertUp target . swapWindows window target
|
|
|
|
|
replaceTarget target =
|
|
|
|
|
windows (modifyStackSet target) >> minimizeWindow target >>
|
|
|
|
|
XS.put (initialValue :: ReplaceOnNew)
|
|
|
|
|
whenJust t replaceTarget
|
|
|
|
|
|
|
|
|
|
maybeReplaceTargetHook = ask >>= (liftX . maybeReplaceTarget) >> return (Endo id)
|
|
|
|
|
|
|
|
|
|
setReplaceTarget = withFocused $ XS.put . Target
|
|
|
|
|
|
|
|
|
|
getWindowWS a = withWindowSet $ \ws -> return $ listToMaybe
|
|
|
|
|
[ w | w <- W.workspaces ws, has a (W.stack w) ]
|
|
|
|
|
where has _ Nothing = False
|
|
|
|
|
has _ (Just _) = True
|
|
|
|
|
|
|
|
|
|
replaceWindow original replacement =
|
|
|
|
|
W.delete original . swapWindows original replacement
|
|
|
|
|
|
2018-06-03 14:28:15 -07:00
|
|
|
|
chromeReplaceKill =
|
2017-07-17 12:32:08 -07:00
|
|
|
|
withFocused $ \w -> do
|
|
|
|
|
vClass <- getClass w
|
|
|
|
|
if vClass == "Chrome" then
|
|
|
|
|
do
|
|
|
|
|
replacement <-
|
|
|
|
|
runMaybeT $ do
|
|
|
|
|
ws <- MaybeT $ join . fmap W.stack <$> getWindowWS w
|
|
|
|
|
MaybeT $
|
|
|
|
|
listToMaybe <$>
|
|
|
|
|
(intersect <$> minimizedWindows <*> windowsWithSameClass w ws)
|
|
|
|
|
let doReplace rep = do
|
|
|
|
|
maximizeWindow rep
|
|
|
|
|
windows $ replaceWindow w rep
|
|
|
|
|
maybe kill doReplace replacement
|
|
|
|
|
else
|
|
|
|
|
kill
|
|
|
|
|
|
2017-09-09 20:27:48 -07:00
|
|
|
|
-- Gather windows of same class
|
|
|
|
|
|
2017-09-20 16:28:26 -07:00
|
|
|
|
allWindows = concat <$> mapWorkspaces (return . W.integrate' . W.stack)
|
2017-09-09 20:27:48 -07:00
|
|
|
|
|
|
|
|
|
windowsMatchingClass klass =
|
|
|
|
|
allWindows >>= filterM (((== klass) <$>) . getClass)
|
|
|
|
|
|
|
|
|
|
gatherClass klass = restoreFocus $
|
2017-10-13 22:10:00 -07:00
|
|
|
|
windowsMatchingClass klass >>= mapM_ doBringWindow
|
2017-09-09 20:27:48 -07:00
|
|
|
|
|
|
|
|
|
gatherThisClass = thisClass >>= flip whenJust gatherClass
|
|
|
|
|
|
2016-11-09 17:29:45 -08:00
|
|
|
|
-- Window switching
|
|
|
|
|
|
2016-10-23 17:32:27 -07:00
|
|
|
|
-- Use greedyView to switch to the correct workspace, and then focus on the
|
|
|
|
|
-- appropriate window within that workspace.
|
2016-11-25 18:48:14 -08:00
|
|
|
|
greedyFocusWindow w ws =
|
|
|
|
|
W.focusWindow w $
|
|
|
|
|
W.greedyView (fromMaybe (W.currentTag ws) $ W.findTag w ws) ws
|
2016-10-23 01:34:31 -07:00
|
|
|
|
|
2016-11-03 13:06:59 -07:00
|
|
|
|
shiftThenView i = W.greedyView i . W.shift i
|
|
|
|
|
|
2016-11-25 11:46:36 -08:00
|
|
|
|
greedyBringWindow w = greedyFocusWindow w . bringWindow w
|
|
|
|
|
|
2016-11-25 18:48:14 -08:00
|
|
|
|
shiftToEmptyAndView =
|
|
|
|
|
doTo Next EmptyWS DWO.getSortByOrder (windows . shiftThenView)
|
2016-11-11 15:48:47 -08:00
|
|
|
|
|
2016-11-29 11:28:17 -08:00
|
|
|
|
setFocusedScreen :: ScreenId -> WindowSet -> WindowSet
|
|
|
|
|
setFocusedScreen to ws =
|
2016-11-29 22:47:44 -06:00
|
|
|
|
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
|
2016-11-29 22:47:44 -06:00
|
|
|
|
, 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
|
|
|
|
|
|
2016-11-29 22:47:44 -06:00
|
|
|
|
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
|
|
|
|
|
|
2016-11-11 15:48:47 -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])
|
|
|
|
|
|
2016-11-25 18:48:14 -08:00
|
|
|
|
swapMinimizeStateAfter action =
|
2016-11-29 15:47:24 -08:00
|
|
|
|
withFocused $ \originalWindow -> do
|
2016-11-25 18:48:14 -08:00
|
|
|
|
_ <- action
|
2016-11-29 15:47:24 -08:00
|
|
|
|
restoreFocus $ do
|
|
|
|
|
maybeUnminimizeFocused
|
|
|
|
|
withFocused $ \newWindow ->
|
|
|
|
|
when (newWindow /= originalWindow) $ minimizeWindow originalWindow
|
2016-11-09 17:29:45 -08:00
|
|
|
|
|
2016-11-21 23:46:16 -06:00
|
|
|
|
-- Named Scratchpads
|
2016-11-24 17:15:57 -06:00
|
|
|
|
|
2016-11-29 15:47:24 -08:00
|
|
|
|
scratchpads =
|
2017-01-16 21:14:49 -08:00
|
|
|
|
[ NS "htop" htopCommand (title =? "htop") nonFloating
|
2016-11-29 15:47:24 -08:00
|
|
|
|
, NS "spotify" spotifyCommand spotifySelector nonFloating
|
|
|
|
|
, NS "hangouts" hangoutsCommand hangoutsSelector nonFloating
|
2016-12-20 17:37:23 -08:00
|
|
|
|
, NS "volume" volumeCommand volumeSelector nonFloating
|
2016-11-29 15:47:24 -08:00
|
|
|
|
]
|
2016-11-21 23:46:16 -06:00
|
|
|
|
|
2017-01-11 12:36:55 -08:00
|
|
|
|
-- TODO: This doesnt work well with minimized windows
|
2016-12-25 15:59:55 -08:00
|
|
|
|
doScratchpad =
|
|
|
|
|
maybeUnminimizeAfter . deactivateFullAnd . namedScratchpadAction scratchpads
|
2016-11-21 23:46:16 -06:00
|
|
|
|
|
2016-11-09 17:29:45 -08:00
|
|
|
|
-- Raise or spawn
|
|
|
|
|
|
2016-11-25 20:22:08 -08:00
|
|
|
|
myRaiseNextMaybe =
|
2016-12-28 21:38:48 -08:00
|
|
|
|
((deactivateFullAnd . maybeUnminimizeAfter) .) .
|
2016-11-25 20:22:08 -08:00
|
|
|
|
raiseNextMaybeCustomFocus greedyFocusWindow
|
|
|
|
|
|
|
|
|
|
myBringNextMaybe =
|
|
|
|
|
((deactivateFullAnd . maybeUnminimizeAfter) .) .
|
|
|
|
|
raiseNextMaybeCustomFocus greedyBringWindow
|
2016-10-26 18:11:18 -07:00
|
|
|
|
|
2017-04-09 13:23:04 -07:00
|
|
|
|
bindBringAndRaise :: KeyMask
|
|
|
|
|
-> KeySym
|
|
|
|
|
-> X ()
|
|
|
|
|
-> Query Bool
|
|
|
|
|
-> [((KeyMask, KeySym), X ())]
|
2016-10-26 18:11:18 -07:00
|
|
|
|
bindBringAndRaise mask sym start query =
|
2017-02-22 17:36:05 -08:00
|
|
|
|
[ ((mask, sym), doRaiseNext)
|
2016-11-26 18:04:48 -08:00
|
|
|
|
, ((mask .|. controlMask, sym), myBringNextMaybe start query)
|
2016-12-28 21:38:48 -08:00
|
|
|
|
, ((mask .|. shiftMask, sym), doRaiseNext)
|
2016-11-26 18:04:48 -08:00
|
|
|
|
]
|
|
|
|
|
where doRaiseNext = myRaiseNextMaybe start query
|
2016-10-26 18:11:18 -07:00
|
|
|
|
|
2017-04-09 13:23:04 -07:00
|
|
|
|
bindBringAndRaiseMany :: [(KeyMask, KeySym, X (), Query Bool)]
|
|
|
|
|
-> [((KeyMask, KeySym), X ())]
|
2016-10-26 18:11:18 -07:00
|
|
|
|
bindBringAndRaiseMany = concatMap (\(a, b, c, d) -> bindBringAndRaise a b c d)
|
2016-11-09 17:29:45 -08:00
|
|
|
|
|
2016-11-22 00:41:04 -08:00
|
|
|
|
-- Screen shift
|
2016-11-24 17:15:57 -06:00
|
|
|
|
|
2016-12-25 15:32:09 -08:00
|
|
|
|
shiftToNextScreen ws =
|
2016-11-22 00:41:04 -08:00
|
|
|
|
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
|
2016-12-24 04:38:03 -08:00
|
|
|
|
|
2017-04-15 23:01:26 -07:00
|
|
|
|
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
|
2017-04-15 23:01:26 -07:00
|
|
|
|
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
|
2017-04-15 23:01:26 -07:00
|
|
|
|
, W.visible = currScreen : trimmedVisible
|
|
|
|
|
}
|
|
|
|
|
where
|
|
|
|
|
currScreen = W.current ws
|
2017-05-30 14:48:52 -07:00
|
|
|
|
nScreen = getNextScreen ws
|
2017-04-15 23:01:26 -07:00
|
|
|
|
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-22 00:41:04 -08:00
|
|
|
|
|
2016-11-09 17:29:45 -08:00
|
|
|
|
-- Key bindings
|
|
|
|
|
|
2018-06-04 13:47:37 -07:00
|
|
|
|
volumeUp = spawn "set_volume.sh --unmute --change-volume +5"
|
|
|
|
|
volumeDown = spawn "set_volume.sh --unmute --change-volume -5"
|
|
|
|
|
mute = spawn "set_volume.sh --toggle-mute"
|
|
|
|
|
|
2017-07-25 01:23:10 -07:00
|
|
|
|
shiftToEmptyOnScreen direction =
|
|
|
|
|
followingWindow (windowToScreen direction True) >> shiftToEmptyAndView
|
|
|
|
|
|
2017-03-10 15:06:20 -08:00
|
|
|
|
addKeys conf@XConfig { modMask = modm } =
|
2016-12-24 19:37:34 -08:00
|
|
|
|
|
2016-12-28 19:41:57 -08:00
|
|
|
|
-- Specific program spawning
|
2016-12-24 19:37:34 -08:00
|
|
|
|
bindBringAndRaiseMany
|
2017-05-30 19:24:04 -07:00
|
|
|
|
[ (modalt, xK_c, spawn chromeCommand, chromeSelector)
|
|
|
|
|
, (modalt, xK_e, spawn emacsCommand, emacsSelector)
|
|
|
|
|
, (modalt, xK_g, spawn gmailCommand, gmailSelector)
|
2016-12-24 19:37:34 -08:00
|
|
|
|
, (modalt, xK_t, spawn transmissionCommand, transmissionSelector)
|
|
|
|
|
] ++
|
|
|
|
|
|
|
|
|
|
-- ScratchPads
|
|
|
|
|
[ ((modalt, xK_m), doScratchpad "htop")
|
|
|
|
|
, ((modalt, xK_v), doScratchpad "volume")
|
|
|
|
|
, ((modalt, xK_h), doScratchpad "hangouts")
|
2017-05-19 13:23:35 -07:00
|
|
|
|
, ((modalt, xK_s), doScratchpad "spotify")
|
2016-12-24 19:39:58 -08:00
|
|
|
|
, ((modalt .|. controlMask, xK_h),
|
|
|
|
|
myRaiseNextMaybe (spawn hangoutsCommand) hangoutsSelector)
|
2016-12-28 20:35:50 -08:00
|
|
|
|
, ((modalt .|. controlMask, xK_s),
|
|
|
|
|
myRaiseNextMaybe (spawn spotifyCommand) spotifySelector)
|
2016-12-24 19:37:34 -08:00
|
|
|
|
|
|
|
|
|
-- 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")
|
2016-12-24 19:37:34 -08:00
|
|
|
|
|
|
|
|
|
-- Window manipulation
|
|
|
|
|
|
2017-03-31 22:36:15 -07:00
|
|
|
|
, ((modm, xK_g), myGoToWindow)
|
|
|
|
|
, ((modm, xK_b), myBringWindow)
|
|
|
|
|
, ((modm .|. shiftMask, xK_b), myReplaceWindow)
|
2017-04-14 21:08:11 -07:00
|
|
|
|
, ((modm .|. controlMask, xK_space), deactivateFullOr goFullscreen)
|
2016-10-03 14:57:58 -07:00
|
|
|
|
, ((modm, xK_m), withFocused minimizeWindow)
|
2016-12-05 19:01:37 -08:00
|
|
|
|
, ((modm .|. shiftMask, xK_m),
|
|
|
|
|
deactivateFullOr $ withLastMinimized maximizeWindowAndFocus)
|
2017-03-31 22:36:15 -07:00
|
|
|
|
, ((modm, xK_x), addHiddenWorkspace "NSP" >> windows (W.shift "NSP"))
|
2016-12-24 19:37:34 -08:00
|
|
|
|
, ((modalt, xK_space), deactivateFullOr restoreOrMinimizeOtherClasses)
|
|
|
|
|
, ((modalt, xK_Return), deactivateFullAnd restoreAllMinimized)
|
2017-07-17 12:32:08 -07:00
|
|
|
|
, ((modm .|. controlMask, xK_t),
|
|
|
|
|
setReplaceTarget >> spawn "chromix-too open chrome://newtab")
|
2018-06-04 13:47:37 -07:00
|
|
|
|
, ((modm .|. controlMask, xK_c), chromeReplaceKill)
|
2017-09-09 20:27:48 -07:00
|
|
|
|
, ((hyper, xK_g), gatherThisClass)
|
2017-05-19 00:52:37 -07:00
|
|
|
|
|
|
|
|
|
-- Directional navigation
|
|
|
|
|
, ((modm, xK_w), windowGo U True)
|
|
|
|
|
, ((modm, xK_s), windowGo D True)
|
|
|
|
|
, ((modm, xK_a), windowGo L True)
|
|
|
|
|
, ((modm, xK_d), windowGo R True)
|
|
|
|
|
|
|
|
|
|
, ((modm .|. shiftMask, xK_w), windowSwap U True)
|
|
|
|
|
, ((modm .|. shiftMask, xK_s), windowSwap D True)
|
|
|
|
|
, ((modm .|. shiftMask, xK_a), windowSwap L True)
|
|
|
|
|
, ((modm .|. shiftMask, xK_d), windowSwap R True)
|
|
|
|
|
|
2017-05-19 13:23:35 -07:00
|
|
|
|
, ((modm .|. controlMask, xK_w), followingWindow $ windowToScreen U True)
|
|
|
|
|
, ((modm .|. controlMask, xK_s), followingWindow $ windowToScreen D True)
|
|
|
|
|
, ((modm .|. controlMask, xK_a), followingWindow $ windowToScreen L True)
|
|
|
|
|
, ((modm .|. controlMask, xK_d), followingWindow $ windowToScreen R True)
|
2017-05-19 00:52:37 -07:00
|
|
|
|
|
2017-05-19 13:23:35 -07:00
|
|
|
|
, ((hyper, xK_w), screenGo U True)
|
|
|
|
|
, ((hyper, xK_s), screenGo D True)
|
|
|
|
|
, ((hyper, xK_a), screenGo L True)
|
|
|
|
|
, ((hyper, xK_d), screenGo R True)
|
2017-05-19 00:52:37 -07:00
|
|
|
|
|
|
|
|
|
, ((hyper .|. shiftMask, xK_w), followingWindow $ screenSwap U True)
|
|
|
|
|
, ((hyper .|. shiftMask, xK_s), followingWindow $ screenSwap D True)
|
|
|
|
|
, ((hyper .|. shiftMask, xK_a), followingWindow $ screenSwap L True)
|
|
|
|
|
, ((hyper .|. shiftMask, xK_d), followingWindow $ screenSwap R True)
|
2017-07-25 01:23:10 -07:00
|
|
|
|
|
|
|
|
|
, ((hyper .|. controlMask, xK_w), shiftToEmptyOnScreen U)
|
|
|
|
|
, ((hyper .|. controlMask, xK_s), shiftToEmptyOnScreen D)
|
|
|
|
|
, ((hyper .|. controlMask, xK_a), shiftToEmptyOnScreen L)
|
|
|
|
|
, ((hyper .|. controlMask, xK_d), shiftToEmptyOnScreen R)
|
2016-12-24 19:37:34 -08:00
|
|
|
|
|
|
|
|
|
-- Focus/Layout manipulation
|
|
|
|
|
|
2016-12-25 15:32:09 -08:00
|
|
|
|
, ((modm, xK_e), goToNextScreenX)
|
2016-12-24 19:37:34 -08:00
|
|
|
|
, ((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)
|
2016-11-21 15:53:00 -08:00
|
|
|
|
, ((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)
|
2016-11-25 18:48:51 -08:00
|
|
|
|
, ((modm .|. shiftMask, xK_h), shiftToEmptyAndView)
|
2017-07-17 12:30:42 -07:00
|
|
|
|
, ((hyper, xK_5), getWorkspaceDmenu >>= windows . SW.swapWithCurrent)
|
2017-01-31 04:14:07 -08:00
|
|
|
|
|
2016-11-10 18:05:50 -08:00
|
|
|
|
-- These need to be rebound to support boringWindows
|
2016-11-10 15:23:37 -08:00
|
|
|
|
, ((modm, xK_m), focusMaster)
|
2016-11-26 18:04:48 -08:00
|
|
|
|
, ((modm, xK_Tab), focusNextClass)
|
2017-03-10 15:06:20 -08:00
|
|
|
|
, ((hyper, xK_e), moveTo Next EmptyWS)
|
2016-12-24 19:37:34 -08: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)
|
2016-12-24 19:37:34 -08:00
|
|
|
|
, ((modalt, xK_4), selectLimit)
|
2017-03-10 15:06:20 -08:00
|
|
|
|
, ((hyper, xK_3), addWorkspacePrompt def)
|
2017-02-16 17:40:58 -08:00
|
|
|
|
, ((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)
|
2016-12-24 19:37:34 -08:00
|
|
|
|
|
|
|
|
|
-- Non-XMonad
|
|
|
|
|
|
2018-05-03 10:39:40 -07:00
|
|
|
|
, ((modm, xK_v), spawn "xclip -o | xdotool type --file -")
|
2017-05-07 23:35:01 -07:00
|
|
|
|
, ((modm .|. controlMask, xK_s), spawn "split_current_chrome_tab.sh")
|
2018-05-03 10:39:40 -07:00
|
|
|
|
, ((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")
|
2017-03-10 17:29:20 -08:00
|
|
|
|
, ((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")
|
|
|
|
|
, ((hyper .|. shiftMask, xK_k),
|
2017-03-01 19:22:39 -08:00
|
|
|
|
spawn "rofi_kill_all.sh")
|
2019-06-26 14:22:59 -07:00
|
|
|
|
, ((hyper, xK_r), spawn "rofi-systemd")
|
2017-03-10 15:06:20 -08:00
|
|
|
|
, ((hyper, xK_0), spawn "tvpower.js")
|
2017-05-07 23:35:01 -07:00
|
|
|
|
, ((modalt, xK_z), spawn "split_chrome_tab_to_next_screen.sh")
|
2017-03-10 15:06:20 -08:00
|
|
|
|
, ((hyper, xK_9), spawn "start_synergy.sh")
|
2017-03-14 13:01:05 -07:00
|
|
|
|
, ((hyper, xK_slash), spawn "toggle_taffybar.sh")
|
2017-03-28 14:55:42 -07:00
|
|
|
|
, ((hyper, xK_space), spawn "skippy-xd")
|
2017-03-30 01:22:00 -07:00
|
|
|
|
, ((hyper, xK_i), spawn "rofi_select_input.hs")
|
2017-04-04 19:46:46 -07:00
|
|
|
|
, ((hyper, xK_o), spawn "rofi_paswitch.sh")
|
2019-06-26 14:22:59 -07:00
|
|
|
|
, ((modm, xK_apostrophe), spawn "load_default_map.sh")
|
|
|
|
|
, ((modalt, xK_apostrophe), spawn "load_xkb_map.sh")
|
2016-12-24 19:37:34 -08:00
|
|
|
|
|
|
|
|
|
-- Media keys
|
2016-11-21 23:46:16 -06:00
|
|
|
|
|
2016-10-05 02:20:35 -07:00
|
|
|
|
-- playerctl
|
2017-05-19 13:23:35 -07:00
|
|
|
|
, ((modm, xK_semicolon), spawn "playerctl play-pause")
|
2016-10-05 03:23:40 -07:00
|
|
|
|
, ((0, xF86XK_AudioPause), spawn "playerctl play-pause")
|
2016-11-22 00:55:13 -06:00
|
|
|
|
, ((0, xF86XK_AudioPlay), spawn "playerctl play-pause")
|
2017-05-19 13:23:35 -07:00
|
|
|
|
, ((modm, xK_l), spawn "playerctl next")
|
2016-10-05 03:23:40 -07:00
|
|
|
|
, ((0, xF86XK_AudioNext), spawn "playerctl next")
|
2017-05-19 13:23:35 -07:00
|
|
|
|
, ((modm, xK_j), spawn "playerctl previous")
|
2016-10-05 03:23:40 -07:00
|
|
|
|
, ((0, xF86XK_AudioPrev), spawn "playerctl previous")
|
|
|
|
|
|
2016-12-24 19:37:34 -08:00
|
|
|
|
-- Volume control
|
2018-06-04 13:47:37 -07:00
|
|
|
|
, ((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")
|
2017-03-02 15:29:38 -08:00
|
|
|
|
|
2016-10-26 18:11:18 -07:00
|
|
|
|
] ++
|
2016-12-24 19:37:34 -08:00
|
|
|
|
|
|
|
|
|
-- Replace moving bindings
|
|
|
|
|
|
2016-09-16 12:50:53 -07:00
|
|
|
|
[((additionalMask .|. modm, key), windows $ function workspace)
|
|
|
|
|
| (workspace, key) <- zip (workspaces conf) [xK_1 .. xK_9]
|
|
|
|
|
, (function, additionalMask) <-
|
|
|
|
|
[ (W.greedyView, 0)
|
|
|
|
|
, (W.shift, shiftMask)
|
2016-12-24 19:37:34 -08:00
|
|
|
|
, (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
|
2016-10-14 03:52:09 -07:00
|
|
|
|
|
|
|
|
|
-- Local Variables:
|
|
|
|
|
-- flycheck-ghc-args: ("-Wno-missing-signatures")
|
2016-11-25 18:49:12 -08:00
|
|
|
|
-- haskell-indent-offset: 2
|
2016-10-14 03:52:09 -07:00
|
|
|
|
-- End:
|