{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
module XMonad.Hooks.Modal
(
modal
, modeWithExit
, mode
, Mode
, mkKeysEz
, setMode
, exitMode
, noModModeLabel
, noModMode
, floatModeLabel
, floatMode
, overlayedFloatModeLabel
, overlayedFloatMode
, floatMap
, overlay
, logMode
) where
import XMonad
import Data.Bits ( (.&.)
, complement
)
import Data.List
import qualified Data.Map.Strict as M
import XMonad.Actions.FloatKeys ( keysMoveWindow
, keysResizeWindow
)
import XMonad.Prelude
import XMonad.Util.EZConfig ( parseKeyCombo
, mkKeymap
)
import qualified XMonad.Util.ExtensibleConf as XC
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Util.Grab
import XMonad.Util.Loggers
import XMonad.Util.Parser ( runParser )
mkKeysEz :: [(String, X ())] -> (XConfig Layout -> M.Map (ButtonMask, KeySym) (X ()))
mkKeysEz :: [(String, X ())]
-> XConfig Layout -> Map (ButtonMask, KeySym) (X ())
mkKeysEz = (XConfig Layout
-> [(String, X ())] -> Map (ButtonMask, KeySym) (X ()))
-> [(String, X ())]
-> XConfig Layout
-> Map (ButtonMask, KeySym) (X ())
forall a b c. (a -> b -> c) -> b -> a -> c
flip XConfig Layout
-> [(String, X ())] -> Map (ButtonMask, KeySym) (X ())
forall (l :: * -> *).
XConfig l -> [(String, X ())] -> Map (ButtonMask, KeySym) (X ())
mkKeymap
data Mode = Mode
{ Mode -> String
label :: !String
, Mode -> XConfig Layout -> Map (ButtonMask, KeySym) (X ())
boundKeys :: !(XConfig Layout -> M.Map (ButtonMask, KeySym) (X ()))
}
newtype ModeConfig = MC [Mode] deriving NonEmpty ModeConfig -> ModeConfig
ModeConfig -> ModeConfig -> ModeConfig
(ModeConfig -> ModeConfig -> ModeConfig)
-> (NonEmpty ModeConfig -> ModeConfig)
-> (forall b. Integral b => b -> ModeConfig -> ModeConfig)
-> Semigroup ModeConfig
forall b. Integral b => b -> ModeConfig -> ModeConfig
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
$c<> :: ModeConfig -> ModeConfig -> ModeConfig
<> :: ModeConfig -> ModeConfig -> ModeConfig
$csconcat :: NonEmpty ModeConfig -> ModeConfig
sconcat :: NonEmpty ModeConfig -> ModeConfig
$cstimes :: forall b. Integral b => b -> ModeConfig -> ModeConfig
stimes :: forall b. Integral b => b -> ModeConfig -> ModeConfig
Semigroup
newtype CurrentMode = CurrentMode
{ CurrentMode -> Maybe Mode
currentMode :: Maybe Mode
}
instance ExtensionClass CurrentMode where
initialValue :: CurrentMode
initialValue = Maybe Mode -> CurrentMode
CurrentMode Maybe Mode
forall a. Maybe a
Nothing
currentKeys :: X (M.Map (ButtonMask, KeySym) (X ()))
currentKeys :: X (Map (ButtonMask, KeySym) (X ()))
currentKeys = do
XConfig Layout
cnf <- (XConf -> XConfig Layout) -> X (XConfig Layout)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks XConf -> XConfig Layout
config
(CurrentMode -> Maybe Mode) -> X (Maybe Mode)
forall a (m :: * -> *) b.
(ExtensionClass a, XLike m) =>
(a -> b) -> m b
XS.gets CurrentMode -> Maybe Mode
currentMode X (Maybe Mode)
-> (Maybe Mode -> X (Map (ButtonMask, KeySym) (X ())))
-> X (Map (ButtonMask, KeySym) (X ()))
forall a b. X a -> (a -> X b) -> X b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just Mode
m -> Map (ButtonMask, KeySym) (X ())
-> X (Map (ButtonMask, KeySym) (X ()))
forall a. a -> X a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Mode -> XConfig Layout -> Map (ButtonMask, KeySym) (X ())
boundKeys Mode
m XConfig Layout
cnf)
Maybe Mode
Nothing -> (XConfig Layout
-> XConfig Layout -> Map (ButtonMask, KeySym) (X ()))
-> XConfig Layout -> Map (ButtonMask, KeySym) (X ())
forall (m :: * -> *) a. Monad m => m (m a) -> m a
join XConfig Layout -> XConfig Layout -> Map (ButtonMask, KeySym) (X ())
forall (l :: * -> *).
XConfig l -> XConfig Layout -> Map (ButtonMask, KeySym) (X ())
keys (XConfig Layout -> Map (ButtonMask, KeySym) (X ()))
-> X (XConfig Layout) -> X (Map (ButtonMask, KeySym) (X ()))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (XConf -> XConfig Layout) -> X (XConfig Layout)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks XConf -> XConfig Layout
config
regrab :: X ()
regrab :: X ()
regrab = [(ButtonMask, KeySym)] -> X ()
grab ([(ButtonMask, KeySym)] -> X ())
-> (Map (ButtonMask, KeySym) (X ()) -> [(ButtonMask, KeySym)])
-> Map (ButtonMask, KeySym) (X ())
-> X ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map (ButtonMask, KeySym) (X ()) -> [(ButtonMask, KeySym)]
forall k a. Map k a -> [k]
M.keys (Map (ButtonMask, KeySym) (X ()) -> X ())
-> X (Map (ButtonMask, KeySym) (X ())) -> X ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< X (Map (ButtonMask, KeySym) (X ()))
currentKeys
refreshMode :: X ()
refreshMode :: X ()
refreshMode = X ()
regrab X () -> X (XConfig Layout) -> X (XConfig Layout)
forall a b. X a -> X b -> X b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (XConf -> XConfig Layout) -> X (XConfig Layout)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks XConf -> XConfig Layout
config X (XConfig Layout) -> (XConfig Layout -> X ()) -> X ()
forall a b. X a -> (a -> X b) -> X b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= XConfig Layout -> X ()
forall (l :: * -> *). XConfig l -> X ()
logHook
modalEventHook :: Event -> X All
modalEventHook :: Event -> X All
modalEventHook = X () -> Event -> X All
customRegrabEvHook X ()
regrab (Event -> X All) -> (Event -> X All) -> Event -> X All
forall a. Semigroup a => a -> a -> a
<> \case
KeyEvent { ev_event_type :: Event -> EventType
ev_event_type = EventType
t, ev_state :: Event -> ButtonMask
ev_state = ButtonMask
m, ev_keycode :: Event -> KeyCode
ev_keycode = KeyCode
code }
| EventType
t EventType -> EventType -> Bool
forall a. Eq a => a -> a -> Bool
== EventType
keyPress -> (Display -> X All) -> X All
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X All) -> X All) -> (Display -> X All) -> X All
forall a b. (a -> b) -> a -> b
$ \Display
dpy -> do
(ButtonMask, KeySym)
kp <- (,) (ButtonMask -> KeySym -> (ButtonMask, KeySym))
-> X ButtonMask -> X (KeySym -> (ButtonMask, KeySym))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ButtonMask -> X ButtonMask
cleanMask ButtonMask
m X (KeySym -> (ButtonMask, KeySym))
-> X KeySym -> X (ButtonMask, KeySym)
forall a b. X (a -> b) -> X a -> X b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> IO KeySym -> X KeySym
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (Display -> KeyCode -> CInt -> IO KeySym
keycodeToKeysym Display
dpy KeyCode
code CInt
0)
Map (ButtonMask, KeySym) (X ())
kbs <- X (Map (ButtonMask, KeySym) (X ()))
currentKeys
() -> X () -> X ()
forall a. a -> X a -> X a
userCodeDef () (Maybe (X ()) -> (X () -> X ()) -> X ()
forall (m :: * -> *) a. Monad m => Maybe a -> (a -> m ()) -> m ()
whenJust ((ButtonMask, KeySym)
-> Map (ButtonMask, KeySym) (X ()) -> Maybe (X ())
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup (ButtonMask, KeySym)
kp Map (ButtonMask, KeySym) (X ())
kbs) X () -> X ()
forall a. a -> a
id)
All -> X All
forall a. a -> X a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> All
All Bool
False)
Event
_ -> All -> X All
forall a. a -> X a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> All
All Bool
True)
modal :: [Mode] -> XConfig l -> XConfig l
modal :: forall (l :: * -> *). [Mode] -> XConfig l -> XConfig l
modal [Mode]
modes = (XConfig l -> XConfig l) -> ModeConfig -> XConfig l -> XConfig l
forall a (l :: * -> *).
(Semigroup a, Typeable a) =>
(XConfig l -> XConfig l) -> a -> XConfig l -> XConfig l
XC.once
(\XConfig l
cnf -> XConfig l
cnf { startupHook = startupHook cnf <> initModes
, handleEventHook = handleEventHook cnf <> modalEventHook
}
)
([Mode] -> ModeConfig
MC [Mode]
modes)
where initModes :: X ()
initModes = CurrentMode -> X ()
forall a (m :: * -> *). (ExtensionClass a, XLike m) => a -> m ()
XS.put (Maybe Mode -> CurrentMode
CurrentMode Maybe Mode
forall a. Maybe a
Nothing) X () -> X () -> X ()
forall a b. X a -> X b -> X b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> X ()
refreshMode
modeWithExit :: String -> String -> (XConfig Layout -> M.Map (KeyMask, KeySym) (X ())) -> Mode
modeWithExit :: String
-> String
-> (XConfig Layout -> Map (ButtonMask, KeySym) (X ()))
-> Mode
modeWithExit String
exitKey String
mlabel XConfig Layout -> Map (ButtonMask, KeySym) (X ())
keys = String
-> (XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode
Mode String
mlabel ((XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode)
-> (XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode
forall a b. (a -> b) -> a -> b
$ \XConfig Layout
cnf ->
let exit :: (ButtonMask, KeySym)
exit = (ButtonMask, KeySym)
-> Maybe (ButtonMask, KeySym) -> (ButtonMask, KeySym)
forall a. a -> Maybe a -> a
fromMaybe (ButtonMask
0, KeySym
xK_Escape) (Maybe (ButtonMask, KeySym) -> (ButtonMask, KeySym))
-> Maybe (ButtonMask, KeySym) -> (ButtonMask, KeySym)
forall a b. (a -> b) -> a -> b
$ Parser (ButtonMask, KeySym) -> String -> Maybe (ButtonMask, KeySym)
forall a. Parser a -> String -> Maybe a
runParser (XConfig Layout -> Parser (ButtonMask, KeySym)
forall (l :: * -> *). XConfig l -> Parser (ButtonMask, KeySym)
parseKeyCombo XConfig Layout
cnf) String
exitKey
in (ButtonMask, KeySym)
-> X ()
-> Map (ButtonMask, KeySym) (X ())
-> Map (ButtonMask, KeySym) (X ())
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert (ButtonMask, KeySym)
exit X ()
exitMode (XConfig Layout -> Map (ButtonMask, KeySym) (X ())
keys XConfig Layout
cnf)
mode :: String -> (XConfig Layout -> M.Map (KeyMask, KeySym) (X ())) -> Mode
mode :: String
-> (XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode
mode = String
-> String
-> (XConfig Layout -> Map (ButtonMask, KeySym) (X ()))
-> Mode
modeWithExit String
"<Escape>"
setMode :: String -> X ()
setMode :: String -> X ()
setMode String
l = do
(ModeConfig -> X ()) -> X ()
forall (m :: * -> *) a b.
(MonadReader XConf m, Typeable a, Monoid b) =>
(a -> m b) -> m b
XC.with ((ModeConfig -> X ()) -> X ()) -> (ModeConfig -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \(MC [Mode]
ls) -> case (Mode -> Bool) -> [Mode] -> Maybe Mode
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
l) (String -> Bool) -> (Mode -> String) -> Mode -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Mode -> String
label) [Mode]
ls of
Maybe Mode
Nothing -> X ()
forall a. Monoid a => a
mempty
Just Mode
m -> do
(CurrentMode -> CurrentMode) -> X ()
forall a (m :: * -> *).
(ExtensionClass a, XLike m) =>
(a -> a) -> m ()
XS.modify ((CurrentMode -> CurrentMode) -> X ())
-> (CurrentMode -> CurrentMode) -> X ()
forall a b. (a -> b) -> a -> b
$ \CurrentMode
cm -> CurrentMode
cm { currentMode = Just m }
X ()
refreshMode
exitMode :: X ()
exitMode :: X ()
exitMode = do
(CurrentMode -> CurrentMode) -> X ()
forall a (m :: * -> *).
(ExtensionClass a, XLike m) =>
(a -> a) -> m ()
XS.modify ((CurrentMode -> CurrentMode) -> X ())
-> (CurrentMode -> CurrentMode) -> X ()
forall a b. (a -> b) -> a -> b
$ \CurrentMode
m -> CurrentMode
m { currentMode = Nothing }
X ()
refreshMode
logMode :: Logger
logMode :: Logger
logMode = (Mode -> String) -> Maybe Mode -> Maybe String
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Mode -> String
label (Maybe Mode -> Maybe String) -> X (Maybe Mode) -> Logger
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (CurrentMode -> Maybe Mode) -> X (Maybe Mode)
forall a (m :: * -> *) b.
(ExtensionClass a, XLike m) =>
(a -> b) -> m b
XS.gets CurrentMode -> Maybe Mode
currentMode
noModModeLabel, floatModeLabel, overlayedFloatModeLabel :: String
noModModeLabel :: String
noModModeLabel = String
"NoMod"
floatModeLabel :: String
floatModeLabel = String
"Float"
overlayedFloatModeLabel :: String
overlayedFloatModeLabel = String
"Overlayed Float"
noModMode :: Mode
noModMode :: Mode
noModMode =
String
-> (XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode
mode String
noModModeLabel ((XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode)
-> (XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode
forall a b. (a -> b) -> a -> b
$ \XConfig Layout
cnf -> ButtonMask
-> Map (ButtonMask, KeySym) (X ())
-> Map (ButtonMask, KeySym) (X ())
stripModifier (XConfig Layout -> ButtonMask
forall (l :: * -> *). XConfig l -> ButtonMask
modMask XConfig Layout
cnf) (XConfig Layout -> XConfig Layout -> Map (ButtonMask, KeySym) (X ())
forall (l :: * -> *).
XConfig l -> XConfig Layout -> Map (ButtonMask, KeySym) (X ())
keys XConfig Layout
cnf XConfig Layout
cnf)
floatMap
:: KeyMask
-> KeyMask
-> KeyMask
-> Int
-> M.Map (ButtonMask, KeySym) (X ())
floatMap :: ButtonMask
-> ButtonMask
-> ButtonMask
-> Int
-> Map (ButtonMask, KeySym) (X ())
floatMap ButtonMask
move ButtonMask
enlarge ButtonMask
shrink Int
s = [((ButtonMask, KeySym), X ())] -> Map (ButtonMask, KeySym) (X ())
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList
[
((ButtonMask
move, KeySym
xK_h) , (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> KeySym -> X ()
keysMoveWindow (-Int
s, Int
0)))
, ((ButtonMask
move, KeySym
xK_j) , (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> KeySym -> X ()
keysMoveWindow (Int
0, Int
s)))
, ((ButtonMask
move, KeySym
xK_k) , (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> KeySym -> X ()
keysMoveWindow (Int
0, -Int
s)))
, ((ButtonMask
move, KeySym
xK_l) , (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> KeySym -> X ()
keysMoveWindow (Int
s, Int
0)))
, ((ButtonMask
enlarge, KeySym
xK_h), (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> G -> KeySym -> X ()
keysResizeWindow (Int
s, Int
0) (Rational
1, Rational
0)))
, ((ButtonMask
enlarge, KeySym
xK_j), (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> G -> KeySym -> X ()
keysResizeWindow (Int
0, Int
s) (Rational
0, Rational
0)))
, ((ButtonMask
enlarge, KeySym
xK_k), (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> G -> KeySym -> X ()
keysResizeWindow (Int
0, Int
s) (Rational
0, Rational
1)))
, ((ButtonMask
enlarge, KeySym
xK_l), (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> G -> KeySym -> X ()
keysResizeWindow (Int
s, Int
0) (Rational
0, Rational
0)))
, ((ButtonMask
shrink, KeySym
xK_h), (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> G -> KeySym -> X ()
keysResizeWindow (-Int
s, Int
0) (Rational
0, Rational
0)))
, ((ButtonMask
shrink, KeySym
xK_j), (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> G -> KeySym -> X ()
keysResizeWindow (Int
0, -Int
s) (Rational
0, Rational
1)))
, ((ButtonMask
shrink, KeySym
xK_k), (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> G -> KeySym -> X ()
keysResizeWindow (Int
0, -Int
s) (Rational
0, Rational
0)))
, ((ButtonMask
shrink, KeySym
xK_l), (KeySym -> X ()) -> X ()
withFocused (ChangeDim -> G -> KeySym -> X ()
keysResizeWindow (-Int
s, Int
0) (Rational
1, Rational
0)))
, ((ButtonMask
noModMask, KeySym
xK_Escape), X ()
exitMode)
]
floatMode
:: Int
-> Mode
floatMode :: Int -> Mode
floatMode Int
i = String
-> (XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode
mode String
floatModeLabel ((XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode)
-> (XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode
forall a b. (a -> b) -> a -> b
$ \XConfig { ButtonMask
modMask :: forall (l :: * -> *). XConfig l -> ButtonMask
modMask :: ButtonMask
modMask } ->
ButtonMask
-> ButtonMask
-> ButtonMask
-> Int
-> Map (ButtonMask, KeySym) (X ())
floatMap ButtonMask
noModMask ButtonMask
modMask (ButtonMask
modMask ButtonMask -> ButtonMask -> ButtonMask
forall a. Bits a => a -> a -> a
.|. ButtonMask
shiftMask) Int
i
overlayedFloatMode
:: Int
-> Mode
overlayedFloatMode :: Int -> Mode
overlayedFloatMode = String -> Mode -> Mode
overlay String
overlayedFloatModeLabel (Mode -> Mode) -> (Int -> Mode) -> Int -> Mode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Mode
floatMode
overlay
:: String
-> Mode
-> Mode
overlay :: String -> Mode -> Mode
overlay String
label Mode
m = String
-> (XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode
Mode String
label ((XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode)
-> (XConfig Layout -> Map (ButtonMask, KeySym) (X ())) -> Mode
forall a b. (a -> b) -> a -> b
$ \XConfig Layout
cnf -> Mode -> XConfig Layout -> Map (ButtonMask, KeySym) (X ())
boundKeys Mode
m XConfig Layout
cnf Map (ButtonMask, KeySym) (X ())
-> Map (ButtonMask, KeySym) (X ())
-> Map (ButtonMask, KeySym) (X ())
forall a. Semigroup a => a -> a -> a
<> XConfig Layout -> XConfig Layout -> Map (ButtonMask, KeySym) (X ())
forall (l :: * -> *).
XConfig l -> XConfig Layout -> Map (ButtonMask, KeySym) (X ())
keys XConfig Layout
cnf XConfig Layout
cnf
stripModifier
:: ButtonMask
-> M.Map (ButtonMask, KeySym) (X ())
-> M.Map (ButtonMask, KeySym) (X ())
stripModifier :: ButtonMask
-> Map (ButtonMask, KeySym) (X ())
-> Map (ButtonMask, KeySym) (X ())
stripModifier ButtonMask
mask = ((ButtonMask, KeySym) -> (ButtonMask, KeySym))
-> Map (ButtonMask, KeySym) (X ())
-> Map (ButtonMask, KeySym) (X ())
forall k2 k1 a. Ord k2 => (k1 -> k2) -> Map k1 a -> Map k2 a
M.mapKeys (((ButtonMask, KeySym) -> (ButtonMask, KeySym))
-> Map (ButtonMask, KeySym) (X ())
-> Map (ButtonMask, KeySym) (X ()))
-> ((ButtonMask, KeySym) -> (ButtonMask, KeySym))
-> Map (ButtonMask, KeySym) (X ())
-> Map (ButtonMask, KeySym) (X ())
forall a b. (a -> b) -> a -> b
$ \(ButtonMask
m, KeySym
k) -> (ButtonMask
m ButtonMask -> ButtonMask -> ButtonMask
forall a. Bits a => a -> a -> a
.&. ButtonMask -> ButtonMask
forall a. Bits a => a -> a
complement ButtonMask
mask, KeySym
k)