{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE ScopedTypeVariables #-}
module XMonad.Actions.EasyMotion (
selectWindow
, EasyMotionConfig(..)
, ChordKeys(..)
, def
, fullSize
, fixedSize
, textSize
, proportional
, bar
) where
import XMonad
import XMonad.Prelude
import qualified XMonad.StackSet as W
import XMonad.Util.Font (releaseXMF, initXMF, Align(AlignCenter), XMonadFont(..), textExtentsXMF)
import XMonad.Util.XUtils (createNewWindow, paintAndWrite, deleteWindow, showWindow)
import Control.Arrow ((&&&))
import qualified Data.Map.Strict as M (Map, elems, map, mapWithKey)
data OverlayWindow =
OverlayWindow { OverlayWindow -> EventMask
win :: !Window
, OverlayWindow -> WindowAttributes
attrs :: !WindowAttributes
, OverlayWindow -> EventMask
overlay :: !Window
, OverlayWindow -> Rectangle
rect :: !Rectangle
}
data Overlay =
Overlay { Overlay -> OverlayWindow
overlayWin :: !OverlayWindow
, Overlay -> [EventMask]
chord :: ![KeySym]
}
data ChordKeys = AnyKeys ![KeySym]
| PerScreenKeys !(M.Map ScreenId [KeySym])
data EasyMotionConfig =
EMConf { EasyMotionConfig -> WorkspaceId
txtCol :: !String
, EasyMotionConfig -> WorkspaceId
bgCol :: !String
, EasyMotionConfig -> Position -> Rectangle -> Rectangle
overlayF :: !(Position -> Rectangle -> Rectangle)
, EasyMotionConfig -> WorkspaceId
borderCol :: !String
, EasyMotionConfig -> ChordKeys
sKeys :: !ChordKeys
, EasyMotionConfig -> EventMask
cancelKey :: !KeySym
, EasyMotionConfig -> WorkspaceId
emFont :: !String
, EasyMotionConfig -> Int
borderPx :: !Int
, EasyMotionConfig -> Int
maxChordLen :: !Int
}
instance Default EasyMotionConfig where
def :: EasyMotionConfig
def =
EMConf { txtCol :: WorkspaceId
txtCol = WorkspaceId
"#ffffff"
, bgCol :: WorkspaceId
bgCol = WorkspaceId
"#000000"
, overlayF :: Position -> Rectangle -> Rectangle
overlayF = Double -> Position -> Rectangle -> Rectangle
forall f. RealFrac f => f -> Position -> Rectangle -> Rectangle
proportional (Double
0.3::Double)
, borderCol :: WorkspaceId
borderCol = WorkspaceId
"#ffffff"
, sKeys :: ChordKeys
sKeys = [EventMask] -> ChordKeys
AnyKeys [EventMask
xK_s, EventMask
xK_d, EventMask
xK_f, EventMask
xK_j, EventMask
xK_k, EventMask
xK_l]
, cancelKey :: EventMask
cancelKey = EventMask
xK_q
, borderPx :: Int
borderPx = Int
1
, maxChordLen :: Int
maxChordLen = Int
0
#ifdef XFT
, emFont :: WorkspaceId
emFont = WorkspaceId
"xft:Sans-100"
#else
, emFont = "-misc-fixed-*-*-*-*-200-*-*-*-*-*-*-*"
#endif
}
fullSize :: Position -> Rectangle -> Rectangle
fullSize :: Position -> Rectangle -> Rectangle
fullSize Position
_ = Rectangle -> Rectangle
forall a. a -> a
id
proportional :: RealFrac f => f -> Position -> Rectangle -> Rectangle
proportional :: forall f. RealFrac f => f -> Position -> Rectangle -> Rectangle
proportional f
f Position
th Rectangle
r = Rectangle { rect_width :: EventType
rect_width = EventType
newW
, rect_height :: EventType
rect_height = EventType
newH
, rect_x :: Position
rect_x = Rectangle -> Position
rect_x Rectangle
r Position -> Position -> Position
forall a. Num a => a -> a -> a
+ EventType -> Position
forall a b. (Integral a, Num b) => a -> b
fi (Rectangle -> EventType
rect_width Rectangle
r EventType -> EventType -> EventType
forall a. Num a => a -> a -> a
- EventType
newW) Position -> Position -> Position
forall a. Integral a => a -> a -> a
`div` Position
2
, rect_y :: Position
rect_y = Rectangle -> Position
rect_y Rectangle
r Position -> Position -> Position
forall a. Num a => a -> a -> a
+ EventType -> Position
forall a b. (Integral a, Num b) => a -> b
fi (Rectangle -> EventType
rect_height Rectangle
r EventType -> EventType -> EventType
forall a. Num a => a -> a -> a
- EventType
newH) Position -> Position -> Position
forall a. Integral a => a -> a -> a
`div` Position
2 }
where
newH :: EventType
newH = EventType -> EventType -> EventType
forall a. Ord a => a -> a -> a
max (Position -> EventType
forall a b. (Integral a, Num b) => a -> b
fi Position
th) (f -> EventType
forall b. Integral b => f -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (f -> EventType) -> f -> EventType
forall a b. (a -> b) -> a -> b
$ f
f f -> f -> f
forall a. Num a => a -> a -> a
* EventType -> f
forall a b. (Integral a, Num b) => a -> b
fi (Rectangle -> EventType
rect_height Rectangle
r))
newW :: EventType
newW = EventType
newH
fixedSize :: (Integral a, Integral b) => a -> b -> Position -> Rectangle -> Rectangle
fixedSize :: forall a b.
(Integral a, Integral b) =>
a -> b -> Position -> Rectangle -> Rectangle
fixedSize a
w b
h Position
th Rectangle
r = Rectangle { rect_width :: EventType
rect_width = EventType
rw
, rect_height :: EventType
rect_height = EventType
rh
, rect_x :: Position
rect_x = Rectangle -> Position
rect_x Rectangle
r Position -> Position -> Position
forall a. Num a => a -> a -> a
+ EventType -> Position
forall a b. (Integral a, Num b) => a -> b
fi (Rectangle -> EventType
rect_width Rectangle
r EventType -> EventType -> EventType
forall a. Num a => a -> a -> a
- EventType
rw) Position -> Position -> Position
forall a. Integral a => a -> a -> a
`div` Position
2
, rect_y :: Position
rect_y = Rectangle -> Position
rect_y Rectangle
r Position -> Position -> Position
forall a. Num a => a -> a -> a
+ EventType -> Position
forall a b. (Integral a, Num b) => a -> b
fi (Rectangle -> EventType
rect_height Rectangle
r EventType -> EventType -> EventType
forall a. Num a => a -> a -> a
- EventType
rh) Position -> Position -> Position
forall a. Integral a => a -> a -> a
`div` Position
2 }
where
rw :: EventType
rw = EventType -> EventType -> EventType
forall a. Ord a => a -> a -> a
max (a -> EventType
forall a b. (Integral a, Num b) => a -> b
fi a
w) (Position -> EventType
forall a b. (Integral a, Num b) => a -> b
fi Position
th)
rh :: EventType
rh = EventType -> EventType -> EventType
forall a. Ord a => a -> a -> a
max (b -> EventType
forall a b. (Integral a, Num b) => a -> b
fi b
h) (Position -> EventType
forall a b. (Integral a, Num b) => a -> b
fi Position
th)
textSize :: Position -> Rectangle -> Rectangle
textSize :: Position -> Rectangle -> Rectangle
textSize Position
th Rectangle
r = Rectangle { rect_width :: EventType
rect_width = Position -> EventType
forall a b. (Integral a, Num b) => a -> b
fi Position
th
, rect_height :: EventType
rect_height = Position -> EventType
forall a b. (Integral a, Num b) => a -> b
fi Position
th
, rect_x :: Position
rect_x = Rectangle -> Position
rect_x Rectangle
r Position -> Position -> Position
forall a. Num a => a -> a -> a
+ (EventType -> Position
forall a b. (Integral a, Num b) => a -> b
fi (Rectangle -> EventType
rect_width Rectangle
r) Position -> Position -> Position
forall a. Num a => a -> a -> a
- Position -> Position
forall a b. (Integral a, Num b) => a -> b
fi Position
th) Position -> Position -> Position
forall a. Integral a => a -> a -> a
`div` Position
2
, rect_y :: Position
rect_y = Rectangle -> Position
rect_y Rectangle
r Position -> Position -> Position
forall a. Num a => a -> a -> a
+ (EventType -> Position
forall a b. (Integral a, Num b) => a -> b
fi (Rectangle -> EventType
rect_height Rectangle
r) Position -> Position -> Position
forall a. Num a => a -> a -> a
- Position -> Position
forall a b. (Integral a, Num b) => a -> b
fi Position
th) Position -> Position -> Position
forall a. Integral a => a -> a -> a
`div` Position
2 }
bar :: RealFrac f => f -> Position -> Rectangle -> Rectangle
bar :: forall f. RealFrac f => f -> Position -> Rectangle -> Rectangle
bar f
f Position
th Rectangle
r = Rectangle { rect_width :: EventType
rect_width = Rectangle -> EventType
rect_width Rectangle
r
, rect_height :: EventType
rect_height = Position -> EventType
forall a b. (Integral a, Num b) => a -> b
fi Position
th
, rect_x :: Position
rect_x = Rectangle -> Position
rect_x Rectangle
r
, rect_y :: Position
rect_y = Rectangle -> Position
rect_y Rectangle
r Position -> Position -> Position
forall a. Num a => a -> a -> a
+ f -> Position
forall b. Integral b => f -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (f
f' f -> f -> f
forall a. Num a => a -> a -> a
* (EventType -> f
forall a b. (Integral a, Num b) => a -> b
fi (Rectangle -> EventType
rect_height Rectangle
r) f -> f -> f
forall a. Num a => a -> a -> a
- Position -> f
forall a b. (Integral a, Num b) => a -> b
fi Position
th)) }
where
f' :: f
f' = f -> f -> f
forall a. Ord a => a -> a -> a
min f
0.0 (f -> f) -> f -> f
forall a b. (a -> b) -> a -> b
$ f -> f -> f
forall a. Ord a => a -> a -> a
max f
f f
1.0
handleSelectWindow :: EasyMotionConfig -> X (Maybe Window)
handleSelectWindow :: EasyMotionConfig -> X (Maybe EventMask)
handleSelectWindow EMConf { sKeys :: EasyMotionConfig -> ChordKeys
sKeys = AnyKeys [] } = Maybe EventMask -> X (Maybe EventMask)
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe EventMask
forall a. Maybe a
Nothing
handleSelectWindow EasyMotionConfig
c = do
XMonadFont
f <- WorkspaceId -> X XMonadFont
initXMF (WorkspaceId -> X XMonadFont) -> WorkspaceId -> X XMonadFont
forall a b. (a -> b) -> a -> b
$ EasyMotionConfig -> WorkspaceId
emFont EasyMotionConfig
c
Position
th <- (\(Position
asc, Position
dsc) -> Position
asc Position -> Position -> Position
forall a. Num a => a -> a -> a
+ Position
dsc Position -> Position -> Position
forall a. Num a => a -> a -> a
+ Position
2) ((Position, Position) -> Position)
-> X (Position, Position) -> X Position
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> XMonadFont -> WorkspaceId -> X (Position, Position)
forall (m :: * -> *).
MonadIO m =>
XMonadFont -> WorkspaceId -> m (Position, Position)
textExtentsXMF XMonadFont
f ((EventMask -> WorkspaceId) -> [EventMask] -> WorkspaceId
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap EventMask -> WorkspaceId
keysymToString (ChordKeys -> [EventMask]
allKeys (ChordKeys -> [EventMask])
-> (EasyMotionConfig -> ChordKeys)
-> EasyMotionConfig
-> [EventMask]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EasyMotionConfig -> ChordKeys
sKeys (EasyMotionConfig -> [EventMask])
-> EasyMotionConfig -> [EventMask]
forall a b. (a -> b) -> a -> b
$ EasyMotionConfig
c))
XConf { theRoot :: XConf -> EventMask
theRoot = EventMask
rw, display :: XConf -> Display
display = Display
dpy } <- X XConf
forall r (m :: * -> *). MonadReader r m => m r
ask
XState { mapped :: XState -> Set EventMask
mapped = Set EventMask
mappedWins, windowset :: XState -> WindowSet
windowset = WindowSet
ws } <- X XState
forall s (m :: * -> *). MonadState s m => m s
get
[Overlay]
overlays :: [Overlay] <- case EasyMotionConfig -> ChordKeys
sKeys EasyMotionConfig
c of
AnyKeys [EventMask]
ks -> [EventMask] -> [OverlayWindow] -> [Overlay]
buildOverlays [EventMask]
ks ([OverlayWindow] -> [Overlay]) -> X [OverlayWindow] -> X [Overlay]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> X [OverlayWindow]
sortedOverlayWindows
where
visibleWindows :: [Window]
visibleWindows :: [EventMask]
visibleWindows = Set EventMask -> [Item (Set EventMask)]
forall l. IsList l => l -> [Item l]
toList Set EventMask
mappedWins
sortedOverlayWindows :: X [OverlayWindow]
sortedOverlayWindows :: X [OverlayWindow]
sortedOverlayWindows = [OverlayWindow] -> [OverlayWindow]
sortOverlayWindows ([OverlayWindow] -> [OverlayWindow])
-> X [OverlayWindow] -> X [OverlayWindow]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Position -> [EventMask] -> X [OverlayWindow]
buildOverlayWindows Position
th [EventMask]
visibleWindows
PerScreenKeys Map ScreenId [EventMask]
m ->
([[Overlay]] -> [Overlay]) -> X [[Overlay]] -> X [Overlay]
forall a b. (a -> b) -> X a -> X b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [[Overlay]] -> [Overlay]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
(X [[Overlay]] -> X [Overlay]) -> X [[Overlay]] -> X [Overlay]
forall a b. (a -> b) -> a -> b
$ [X [Overlay]] -> X [[Overlay]]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence
([X [Overlay]] -> X [[Overlay]]) -> [X [Overlay]] -> X [[Overlay]]
forall a b. (a -> b) -> a -> b
$ Map ScreenId (X [Overlay]) -> [X [Overlay]]
forall k a. Map k a -> [a]
M.elems
(Map ScreenId (X [Overlay]) -> [X [Overlay]])
-> Map ScreenId (X [Overlay]) -> [X [Overlay]]
forall a b. (a -> b) -> a -> b
$ (ScreenId -> [EventMask] -> X [Overlay])
-> Map ScreenId [EventMask] -> Map ScreenId (X [Overlay])
forall k a b. (k -> a -> b) -> Map k a -> Map k b
M.mapWithKey (\ScreenId
sid [EventMask]
ks -> [EventMask] -> [OverlayWindow] -> [Overlay]
buildOverlays [EventMask]
ks ([OverlayWindow] -> [Overlay]) -> X [OverlayWindow] -> X [Overlay]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ScreenId -> X [OverlayWindow]
sortedOverlayWindows ScreenId
sid) Map ScreenId [EventMask]
m
where
screenById :: ScreenId -> Maybe WindowScreen
screenById :: ScreenId -> Maybe WindowScreen
screenById ScreenId
sid = (WindowScreen -> Bool) -> [WindowScreen] -> Maybe WindowScreen
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((ScreenId -> ScreenId -> Bool
forall a. Eq a => a -> a -> Bool
== ScreenId
sid) (ScreenId -> Bool)
-> (WindowScreen -> ScreenId) -> WindowScreen -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WindowScreen -> ScreenId
forall i l a sid sd. Screen i l a sid sd -> sid
W.screen) (WindowSet -> [WindowScreen]
forall i l a s sd. StackSet i l a s sd -> [Screen i l a s sd]
W.screens WindowSet
ws)
visibleWindowsOnScreen :: ScreenId -> [Window]
visibleWindowsOnScreen :: ScreenId -> [EventMask]
visibleWindowsOnScreen ScreenId
sid = (EventMask -> Bool) -> [EventMask] -> [EventMask]
forall a. (a -> Bool) -> [a] -> [a]
filter (EventMask -> [EventMask] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Set EventMask -> [Item (Set EventMask)]
forall l. IsList l => l -> [Item l]
toList Set EventMask
mappedWins) ([EventMask] -> [EventMask]) -> [EventMask] -> [EventMask]
forall a b. (a -> b) -> a -> b
$ Maybe (Stack EventMask) -> [EventMask]
forall a. Maybe (Stack a) -> [a]
W.integrate' (Maybe (Stack EventMask) -> [EventMask])
-> Maybe (Stack EventMask) -> [EventMask]
forall a b. (a -> b) -> a -> b
$ ScreenId -> Maybe WindowScreen
screenById ScreenId
sid Maybe WindowScreen
-> (WindowScreen -> Maybe (Stack EventMask))
-> Maybe (Stack EventMask)
forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Workspace WorkspaceId (Layout EventMask) EventMask
-> Maybe (Stack EventMask)
forall i l a. Workspace i l a -> Maybe (Stack a)
W.stack (Workspace WorkspaceId (Layout EventMask) EventMask
-> Maybe (Stack EventMask))
-> (WindowScreen
-> Workspace WorkspaceId (Layout EventMask) EventMask)
-> WindowScreen
-> Maybe (Stack EventMask)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WindowScreen -> Workspace WorkspaceId (Layout EventMask) EventMask
forall i l a sid sd. Screen i l a sid sd -> Workspace i l a
W.workspace
sortedOverlayWindows :: ScreenId -> X [OverlayWindow]
sortedOverlayWindows :: ScreenId -> X [OverlayWindow]
sortedOverlayWindows ScreenId
sid = [OverlayWindow] -> [OverlayWindow]
sortOverlayWindows ([OverlayWindow] -> [OverlayWindow])
-> X [OverlayWindow] -> X [OverlayWindow]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Position -> [EventMask] -> X [OverlayWindow]
buildOverlayWindows Position
th (ScreenId -> [EventMask]
visibleWindowsOnScreen ScreenId
sid)
CInt
status <- IO CInt -> X CInt
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO CInt -> X CInt) -> IO CInt -> X CInt
forall a b. (a -> b) -> a -> b
$ Display
-> EventMask -> Bool -> CInt -> CInt -> EventMask -> IO CInt
grabKeyboard Display
dpy EventMask
rw Bool
True CInt
grabModeAsync CInt
grabModeAsync EventMask
currentTime
if CInt
status CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
grabSuccess
then do
HandleResult
resultWin <- Display
-> (Overlay -> X ())
-> EventMask
-> [Overlay]
-> [Overlay]
-> X HandleResult
handleKeyboard Display
dpy (XMonadFont -> Overlay -> X ()
displayOverlay XMonadFont
f) (EasyMotionConfig -> EventMask
cancelKey EasyMotionConfig
c) [Overlay]
overlays []
IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ Display -> EventMask -> IO ()
ungrabKeyboard Display
dpy EventMask
currentTime
(Overlay -> X ()) -> [Overlay] -> X ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (EventMask -> X ()
deleteWindow (EventMask -> X ()) -> (Overlay -> EventMask) -> Overlay -> X ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OverlayWindow -> EventMask
overlay (OverlayWindow -> EventMask)
-> (Overlay -> OverlayWindow) -> Overlay -> EventMask
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Overlay -> OverlayWindow
overlayWin) [Overlay]
overlays
IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ Display -> Bool -> IO ()
sync Display
dpy Bool
False
XMonadFont -> X ()
releaseXMF XMonadFont
f
case HandleResult
resultWin of
Selected Overlay
o -> Maybe EventMask -> X (Maybe EventMask)
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe EventMask -> X (Maybe EventMask))
-> (Overlay -> Maybe EventMask) -> Overlay -> X (Maybe EventMask)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EventMask -> Maybe EventMask
forall a. a -> Maybe a
Just (EventMask -> Maybe EventMask)
-> (Overlay -> EventMask) -> Overlay -> Maybe EventMask
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OverlayWindow -> EventMask
win (OverlayWindow -> EventMask)
-> (Overlay -> OverlayWindow) -> Overlay -> EventMask
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Overlay -> OverlayWindow
overlayWin (Overlay -> X (Maybe EventMask)) -> Overlay -> X (Maybe EventMask)
forall a b. (a -> b) -> a -> b
$ Overlay
o
HandleResult
_ -> Maybe EventMask -> (EventMask -> X ()) -> X ()
forall (m :: * -> *) a. Monad m => Maybe a -> (a -> m ()) -> m ()
whenJust (WindowSet -> Maybe EventMask
forall i l a s sd. StackSet i l a s sd -> Maybe a
W.peek WindowSet
ws) ((WindowSet -> WindowSet) -> X ()
windows ((WindowSet -> WindowSet) -> X ())
-> (EventMask -> WindowSet -> WindowSet) -> EventMask -> X ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EventMask -> WindowSet -> WindowSet
forall s a i l sd.
(Eq s, Eq a, Eq i) =>
a -> StackSet i l a s sd -> StackSet i l a s sd
W.focusWindow) X () -> Maybe EventMask -> X (Maybe EventMask)
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> Maybe EventMask
forall a. Maybe a
Nothing
else XMonadFont -> X ()
releaseXMF XMonadFont
f X () -> Maybe EventMask -> X (Maybe EventMask)
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> Maybe EventMask
forall a. Maybe a
Nothing
where
allKeys :: ChordKeys -> [KeySym]
allKeys :: ChordKeys -> [EventMask]
allKeys (AnyKeys [EventMask]
ks) = [EventMask]
ks
allKeys (PerScreenKeys Map ScreenId [EventMask]
m) = [[EventMask]] -> [EventMask]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[EventMask]] -> [EventMask]) -> [[EventMask]] -> [EventMask]
forall a b. (a -> b) -> a -> b
$ Map ScreenId [EventMask] -> [[EventMask]]
forall k a. Map k a -> [a]
M.elems Map ScreenId [EventMask]
m
buildOverlays :: [KeySym] -> [OverlayWindow] -> [Overlay]
buildOverlays :: [EventMask] -> [OverlayWindow] -> [Overlay]
buildOverlays = Int -> [EventMask] -> [OverlayWindow] -> [Overlay]
appendChords (EasyMotionConfig -> Int
maxChordLen EasyMotionConfig
c)
buildOverlayWindows :: Position -> [Window] -> X [OverlayWindow]
buildOverlayWindows :: Position -> [EventMask] -> X [OverlayWindow]
buildOverlayWindows Position
th = ([Maybe OverlayWindow] -> [OverlayWindow])
-> X [Maybe OverlayWindow] -> X [OverlayWindow]
forall a b. (a -> b) -> X a -> X b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([OverlayWindow] -> Maybe [OverlayWindow] -> [OverlayWindow]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [OverlayWindow] -> [OverlayWindow])
-> ([Maybe OverlayWindow] -> Maybe [OverlayWindow])
-> [Maybe OverlayWindow]
-> [OverlayWindow]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe OverlayWindow] -> Maybe [OverlayWindow]
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
forall (f :: * -> *) a. Applicative f => [f a] -> f [a]
sequenceA)
(X [Maybe OverlayWindow] -> X [OverlayWindow])
-> ([EventMask] -> X [Maybe OverlayWindow])
-> [EventMask]
-> X [OverlayWindow]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (EventMask -> X (Maybe OverlayWindow))
-> [EventMask] -> X [Maybe OverlayWindow]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse (Position -> EventMask -> X (Maybe OverlayWindow)
buildOverlayWin Position
th)
sortOverlayWindows :: [OverlayWindow] -> [OverlayWindow]
sortOverlayWindows :: [OverlayWindow] -> [OverlayWindow]
sortOverlayWindows = (OverlayWindow -> (CInt, CInt))
-> [OverlayWindow] -> [OverlayWindow]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn ((WindowAttributes -> CInt
wa_x (WindowAttributes -> CInt)
-> (WindowAttributes -> CInt) -> WindowAttributes -> (CInt, CInt)
forall b c c'. (b -> c) -> (b -> c') -> b -> (c, c')
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& WindowAttributes -> CInt
wa_y) (WindowAttributes -> (CInt, CInt))
-> (OverlayWindow -> WindowAttributes)
-> OverlayWindow
-> (CInt, CInt)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OverlayWindow -> WindowAttributes
attrs)
makeRect :: WindowAttributes -> Rectangle
makeRect :: WindowAttributes -> Rectangle
makeRect WindowAttributes
wa = Position -> Position -> EventType -> EventType -> Rectangle
Rectangle (CInt -> Position
forall a b. (Integral a, Num b) => a -> b
fi (WindowAttributes -> CInt
wa_x WindowAttributes
wa)) (CInt -> Position
forall a b. (Integral a, Num b) => a -> b
fi (WindowAttributes -> CInt
wa_y WindowAttributes
wa)) (CInt -> EventType
forall a b. (Integral a, Num b) => a -> b
fi (WindowAttributes -> CInt
wa_width WindowAttributes
wa)) (CInt -> EventType
forall a b. (Integral a, Num b) => a -> b
fi (WindowAttributes -> CInt
wa_height WindowAttributes
wa))
buildOverlayWin :: Position -> Window -> X (Maybe OverlayWindow)
buildOverlayWin :: Position -> EventMask -> X (Maybe OverlayWindow)
buildOverlayWin Position
th EventMask
w = EventMask -> X (Maybe WindowAttributes)
safeGetWindowAttributes EventMask
w X (Maybe WindowAttributes)
-> (Maybe WindowAttributes -> X (Maybe OverlayWindow))
-> X (Maybe OverlayWindow)
forall a b. X a -> (a -> X b) -> X b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe WindowAttributes
Nothing -> Maybe OverlayWindow -> X (Maybe OverlayWindow)
forall a. a -> X a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe OverlayWindow
forall a. Maybe a
Nothing
Just WindowAttributes
wAttrs -> do
let r :: Rectangle
r = EasyMotionConfig -> Position -> Rectangle -> Rectangle
overlayF EasyMotionConfig
c Position
th (Rectangle -> Rectangle) -> Rectangle -> Rectangle
forall a b. (a -> b) -> a -> b
$ WindowAttributes -> Rectangle
makeRect WindowAttributes
wAttrs
EventMask
o <- Rectangle -> Maybe EventMask -> WorkspaceId -> Bool -> X EventMask
createNewWindow Rectangle
r Maybe EventMask
forall a. Maybe a
Nothing WorkspaceId
"" Bool
True
Maybe OverlayWindow -> X (Maybe OverlayWindow)
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe OverlayWindow -> X (Maybe OverlayWindow))
-> (OverlayWindow -> Maybe OverlayWindow)
-> OverlayWindow
-> X (Maybe OverlayWindow)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OverlayWindow -> Maybe OverlayWindow
forall a. a -> Maybe a
Just (OverlayWindow -> X (Maybe OverlayWindow))
-> OverlayWindow -> X (Maybe OverlayWindow)
forall a b. (a -> b) -> a -> b
$ OverlayWindow { rect :: Rectangle
rect=Rectangle
r, overlay :: EventMask
overlay=EventMask
o, win :: EventMask
win=EventMask
w, attrs :: WindowAttributes
attrs=WindowAttributes
wAttrs }
displayOverlay :: XMonadFont -> Overlay -> X ()
displayOverlay :: XMonadFont -> Overlay -> X ()
displayOverlay XMonadFont
f Overlay { overlayWin :: Overlay -> OverlayWindow
overlayWin = OverlayWindow { rect :: OverlayWindow -> Rectangle
rect = Rectangle
r, overlay :: OverlayWindow -> EventMask
overlay = EventMask
o }, chord :: Overlay -> [EventMask]
chord = [EventMask]
ch } = do
EventMask -> X ()
showWindow EventMask
o
EventMask
-> XMonadFont
-> EventType
-> EventType
-> EventType
-> WorkspaceId
-> WorkspaceId
-> WorkspaceId
-> WorkspaceId
-> [Align]
-> [WorkspaceId]
-> X ()
paintAndWrite EventMask
o XMonadFont
f (EventType -> EventType
forall a b. (Integral a, Num b) => a -> b
fi (Rectangle -> EventType
rect_width Rectangle
r)) (EventType -> EventType
forall a b. (Integral a, Num b) => a -> b
fi (Rectangle -> EventType
rect_height Rectangle
r)) (Int -> EventType
forall a b. (Integral a, Num b) => a -> b
fi (EasyMotionConfig -> Int
borderPx EasyMotionConfig
c)) (EasyMotionConfig -> WorkspaceId
bgCol EasyMotionConfig
c) (EasyMotionConfig -> WorkspaceId
borderCol EasyMotionConfig
c) (EasyMotionConfig -> WorkspaceId
txtCol EasyMotionConfig
c) (EasyMotionConfig -> WorkspaceId
bgCol EasyMotionConfig
c) [Align
AlignCenter] [(EventMask -> WorkspaceId) -> [EventMask] -> WorkspaceId
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap EventMask -> WorkspaceId
keysymToString [EventMask]
ch]
selectWindow :: EasyMotionConfig -> X (Maybe Window)
selectWindow :: EasyMotionConfig -> X (Maybe EventMask)
selectWindow EasyMotionConfig
conf =
EasyMotionConfig -> X (Maybe EventMask)
handleSelectWindow EasyMotionConfig
conf { sKeys = sanitiseKeys (sKeys conf) }
where
sanitise :: [KeySym] -> [KeySym]
sanitise :: [EventMask] -> [EventMask]
sanitise = [EventMask] -> [EventMask]
forall a. Eq a => [a] -> [a]
nub ([EventMask] -> [EventMask])
-> ([EventMask] -> [EventMask]) -> [EventMask] -> [EventMask]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (EventMask -> Bool) -> [EventMask] -> [EventMask]
forall a. (a -> Bool) -> [a] -> [a]
filter (EventMask -> [EventMask] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [EventMask
xK_BackSpace, EasyMotionConfig -> EventMask
cancelKey EasyMotionConfig
conf])
sanitiseKeys :: ChordKeys -> ChordKeys
sanitiseKeys :: ChordKeys -> ChordKeys
sanitiseKeys ChordKeys
cKeys =
case ChordKeys
cKeys of
AnyKeys [EventMask]
ks -> [EventMask] -> ChordKeys
AnyKeys ([EventMask] -> ChordKeys)
-> ([EventMask] -> [EventMask]) -> [EventMask] -> ChordKeys
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [EventMask] -> [EventMask]
sanitise ([EventMask] -> ChordKeys) -> [EventMask] -> ChordKeys
forall a b. (a -> b) -> a -> b
$ [EventMask]
ks
PerScreenKeys Map ScreenId [EventMask]
m -> Map ScreenId [EventMask] -> ChordKeys
PerScreenKeys (Map ScreenId [EventMask] -> ChordKeys)
-> Map ScreenId [EventMask] -> ChordKeys
forall a b. (a -> b) -> a -> b
$ ([EventMask] -> [EventMask])
-> Map ScreenId [EventMask] -> Map ScreenId [EventMask]
forall a b k. (a -> b) -> Map k a -> Map k b
M.map [EventMask] -> [EventMask]
sanitise Map ScreenId [EventMask]
m
appendChords :: Int -> [KeySym] -> [OverlayWindow] -> [Overlay]
appendChords :: Int -> [EventMask] -> [OverlayWindow] -> [Overlay]
appendChords Int
_ [] [OverlayWindow]
_ = []
appendChords Int
maxUserSelectedLen [EventMask]
ks [OverlayWindow]
overlayWins =
(OverlayWindow -> [EventMask] -> Overlay)
-> [OverlayWindow] -> [[EventMask]] -> [Overlay]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith OverlayWindow -> [EventMask] -> Overlay
Overlay [OverlayWindow]
overlayWins [[EventMask]]
chords
where
chords :: [[EventMask]]
chords = Int -> [EventMask] -> [[EventMask]]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
chordLen [EventMask]
ks
minCoverLen :: Int
minCoverLen = -((-([OverlayWindow] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [OverlayWindow]
overlayWins)) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` [EventMask] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [EventMask]
ks)
chordLen :: Int
chordLen = if Int
maxUserSelectedLen Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 then Int
minCoverLen else Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
minCoverLen Int
maxUserSelectedLen
data HandleResult = Exit | Selected Overlay | Backspace
handleKeyboard :: Display -> (Overlay -> X()) -> KeySym -> [Overlay] -> [Overlay] -> X HandleResult
handleKeyboard :: Display
-> (Overlay -> X ())
-> EventMask
-> [Overlay]
-> [Overlay]
-> X HandleResult
handleKeyboard Display
_ Overlay -> X ()
_ EventMask
_ [] [Overlay]
_ = HandleResult -> X HandleResult
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return HandleResult
Exit
handleKeyboard Display
dpy Overlay -> X ()
drawFn EventMask
cancel [Overlay]
selected [Overlay]
deselected = do
X [()]
redraw
Event
ev <- IO Event -> X Event
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO Event -> X Event) -> IO Event -> X Event
forall a b. (a -> b) -> a -> b
$ (XEventPtr -> IO Event) -> IO Event
forall a. (XEventPtr -> IO a) -> IO a
allocaXEvent ((XEventPtr -> IO Event) -> IO Event)
-> (XEventPtr -> IO Event) -> IO Event
forall a b. (a -> b) -> a -> b
$ \XEventPtr
e -> do
Display -> EventMask -> XEventPtr -> IO ()
maskEvent Display
dpy (EventMask
keyPressMask EventMask -> EventMask -> EventMask
forall a. Bits a => a -> a -> a
.|. EventMask
keyReleaseMask EventMask -> EventMask -> EventMask
forall a. Bits a => a -> a -> a
.|. EventMask
buttonPressMask) XEventPtr
e
XEventPtr -> IO Event
getEvent XEventPtr
e
if | Event -> EventType
ev_event_type Event
ev EventType -> EventType -> Bool
forall a. Eq a => a -> a -> Bool
== EventType
keyPress -> do
EventMask
s <- IO EventMask -> X EventMask
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO EventMask -> X EventMask) -> IO EventMask -> X EventMask
forall a b. (a -> b) -> a -> b
$ Display -> KeyCode -> CInt -> IO EventMask
keycodeToKeysym Display
dpy (Event -> KeyCode
ev_keycode Event
ev) CInt
0
if | EventMask
s EventMask -> EventMask -> Bool
forall a. Eq a => a -> a -> Bool
== EventMask
cancel -> HandleResult -> X HandleResult
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return HandleResult
Exit
| EventMask
s EventMask -> EventMask -> Bool
forall a. Eq a => a -> a -> Bool
== EventMask
xK_BackSpace -> HandleResult -> X HandleResult
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return HandleResult
Backspace
| EventMask -> Bool
isNextOverlayKey EventMask
s -> EventMask -> X HandleResult
handleNextOverlayKey EventMask
s
| Bool
otherwise -> Display
-> (Overlay -> X ())
-> EventMask
-> [Overlay]
-> [Overlay]
-> X HandleResult
handleKeyboard Display
dpy Overlay -> X ()
drawFn EventMask
cancel [Overlay]
selected [Overlay]
deselected
| Event -> EventType
ev_event_type Event
ev EventType -> EventType -> Bool
forall a. Eq a => a -> a -> Bool
== EventType
buttonPress -> do
IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ Display -> CInt -> EventMask -> IO ()
allowEvents Display
dpy CInt
replayPointer EventMask
currentTime
Display
-> (Overlay -> X ())
-> EventMask
-> [Overlay]
-> [Overlay]
-> X HandleResult
handleKeyboard Display
dpy Overlay -> X ()
drawFn EventMask
cancel [Overlay]
selected [Overlay]
deselected
| Bool
otherwise -> Display
-> (Overlay -> X ())
-> EventMask
-> [Overlay]
-> [Overlay]
-> X HandleResult
handleKeyboard Display
dpy Overlay -> X ()
drawFn EventMask
cancel [Overlay]
selected [Overlay]
deselected
where
redraw :: X [()]
redraw = ([Overlay] -> X ()) -> [[Overlay]] -> X [()]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM ((Overlay -> X ()) -> [Overlay] -> X ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Overlay -> X ()
drawFn) [[Overlay]
selected, [Overlay]
deselected]
retryBackspace :: HandleResult -> X HandleResult
retryBackspace HandleResult
x =
case HandleResult
x of
HandleResult
Backspace -> X [()]
redraw X [()] -> X HandleResult -> X HandleResult
forall a b. X a -> X b -> X b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Display
-> (Overlay -> X ())
-> EventMask
-> [Overlay]
-> [Overlay]
-> X HandleResult
handleKeyboard Display
dpy Overlay -> X ()
drawFn EventMask
cancel [Overlay]
selected [Overlay]
deselected
HandleResult
_ -> HandleResult -> X HandleResult
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return HandleResult
x
isNextOverlayKey :: EventMask -> Bool
isNextOverlayKey EventMask
keySym = Maybe Overlay -> Bool
forall a. Maybe a -> Bool
isJust ((Overlay -> Bool) -> [Overlay] -> Maybe Overlay
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((Maybe EventMask -> Maybe EventMask -> Bool
forall a. Eq a => a -> a -> Bool
== EventMask -> Maybe EventMask
forall a. a -> Maybe a
Just EventMask
keySym) (Maybe EventMask -> Bool)
-> (Overlay -> Maybe EventMask) -> Overlay -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [EventMask] -> Maybe EventMask
forall a. [a] -> Maybe a
listToMaybe ([EventMask] -> Maybe EventMask)
-> (Overlay -> [EventMask]) -> Overlay -> Maybe EventMask
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Overlay -> [EventMask]
chord) [Overlay]
selected)
handleNextOverlayKey :: EventMask -> X HandleResult
handleNextOverlayKey EventMask
keySym =
case [Overlay]
fg of
[Overlay
x] -> HandleResult -> X HandleResult
forall a. a -> X a
forall (m :: * -> *) a. Monad m => a -> m a
return (HandleResult -> X HandleResult) -> HandleResult -> X HandleResult
forall a b. (a -> b) -> a -> b
$ Overlay -> HandleResult
Selected Overlay
x
[Overlay]
_ -> Display
-> (Overlay -> X ())
-> EventMask
-> [Overlay]
-> [Overlay]
-> X HandleResult
handleKeyboard Display
dpy Overlay -> X ()
drawFn EventMask
cancel ([Overlay] -> [Overlay]
trim [Overlay]
fg) ([Overlay] -> [Overlay]
clear [Overlay]
bg) X HandleResult
-> (HandleResult -> X HandleResult) -> X HandleResult
forall a b. X a -> (a -> X b) -> X b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HandleResult -> X HandleResult
retryBackspace
where
([Overlay]
fg, [Overlay]
bg) = (Overlay -> Bool) -> [Overlay] -> ([Overlay], [Overlay])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition ((Maybe EventMask -> Maybe EventMask -> Bool
forall a. Eq a => a -> a -> Bool
== EventMask -> Maybe EventMask
forall a. a -> Maybe a
Just EventMask
keySym) (Maybe EventMask -> Bool)
-> (Overlay -> Maybe EventMask) -> Overlay -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [EventMask] -> Maybe EventMask
forall a. [a] -> Maybe a
listToMaybe ([EventMask] -> Maybe EventMask)
-> (Overlay -> [EventMask]) -> Overlay -> Maybe EventMask
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Overlay -> [EventMask]
chord) [Overlay]
selected
trim :: [Overlay] -> [Overlay]
trim = (Overlay -> Overlay) -> [Overlay] -> [Overlay]
forall a b. (a -> b) -> [a] -> [b]
map (\Overlay
o -> Overlay
o { chord = drop 1 $ chord o })
clear :: [Overlay] -> [Overlay]
clear = (Overlay -> Overlay) -> [Overlay] -> [Overlay]
forall a b. (a -> b) -> [a] -> [b]
map (\Overlay
o -> Overlay
o { chord = [] })