{-# LANGUAGE MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
module XMonad.Layout.TrackFloating
(
trackFloating,
useTransientFor,
TrackFloating,
UseTransientFor,
) where
import Control.Monad
import Data.Function
import Data.List
import Data.Maybe
import qualified Data.Map as M
import qualified Data.Set as S
import XMonad
import XMonad.Layout.LayoutModifier
import qualified XMonad.StackSet as W
import qualified Data.Traversable as T
data TrackFloating a = TrackFloating
{ _wasFloating :: Bool,
_tiledFocus :: Maybe Window }
deriving (Read,Show,Eq)
instance LayoutModifier TrackFloating Window where
modifyLayoutWithUpdate os@(TrackFloating _wasF mw) ws@(W.Workspace{ W.stack = ms }) r
= do
winset <- gets windowset
let xCur = fmap W.focus xStack
xStack = W.stack $ W.workspace $ W.current winset
isF = fmap (\x -> x `M.member` W.floating winset ||
(let (\\\) = (S.\\) `on` (S.fromList . W.integrate')
in x `S.member` (xStack \\\ ms)))
xCur
newStack
| Just isF' <- isF,
isF',
Just w <- mw,
Just s <- ms,
Just ns <- find ((==) w . W.focus)
$ zipWith const (iterate W.focusDown' s) (W.integrate s)
= Just ns
| otherwise
= ms
newState = case isF of
Just True -> mw
Just False | Just f <- xCur -> Just f
_ -> Nothing
ran <- runLayout ws{ W.stack = newStack } r
return (ran,
let n = TrackFloating (fromMaybe False isF) newState
in guard (n /= os) >> Just n)
useTransientFor :: l a -> ModifiedLayout UseTransientFor l a
useTransientFor x = ModifiedLayout UseTransientFor x
data UseTransientFor a = UseTransientFor deriving (Read,Show,Eq)
instance LayoutModifier UseTransientFor Window where
modifyLayout _ ws@(W.Workspace{ W.stack = ms }) r = do
m <- gets (W.peek . windowset)
d <- asks display
parent <- fmap join $ T.traverse (io . getTransientForHint d) m
s0 <- get
whenJust parent $ \p -> put s0{ windowset = W.focusWindow p (windowset s0) }
result <- runLayout ws{ W.stack = fromMaybe ms (liftM2 focusWin ms parent) } r
m' <- gets (W.peek . windowset)
when (m' == parent) $
whenJust m $ \p -> put s0{ windowset = W.focusWindow p (windowset s0) }
return result
focusWin :: Eq a => W.Stack a -> a -> Maybe (W.Stack a)
focusWin st@(W.Stack f u d) w
| w `elem` u || w `elem` d = Just . head . filter ((==w) . W.focus)
$ iterate (if w `elem` u then W.focusUp'
else W.focusDown') st
| w == f = Just st
| otherwise = Nothing
trackFloating :: l a -> ModifiedLayout TrackFloating l a
trackFloating layout = ModifiedLayout (TrackFloating False Nothing) layout