module XMonad.Hooks.ManageHelpers (
Side(..),
composeOne,
(-?>), (/=?), (<==?), (</=?), (-->>), (-?>>),
currentWs,
isInProperty,
isKDETrayWindow,
isFullscreen,
isDialog,
pid,
transientTo,
maybeToDefinite,
MaybeManageHook,
transience,
transience',
doRectFloat,
doFullFloat,
doCenterFloat,
doSideFloat,
doFloatAt,
doFloatDep,
doHideIgnore,
Match,
) where
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Util.WindowProperties (getProp32s)
import Data.Maybe
import Data.Monoid
import System.Posix (ProcessID)
data Side = SC | NC | CE | CW | SE | SW | NE | NW | C
deriving (Read, Show, Eq)
type MaybeManageHook = Query (Maybe (Endo WindowSet))
data Match a = Match Bool a
composeOne :: [MaybeManageHook] -> ManageHook
composeOne = foldr try idHook
where
try q z = do
x <- q
case x of
Just h -> return h
Nothing -> z
infixr 0 -?>, -->>, -?>>
(/=?) :: Eq a => Query a -> a -> Query Bool
q /=? x = fmap (/= x) q
(<==?) :: Eq a => Query a -> a -> Query (Match a)
q <==? x = fmap (`eq` x) q
where
eq q' x' = Match (q' == x') q'
(</=?) :: Eq a => Query a -> a -> Query (Match a)
q </=? x = fmap (`neq` x) q
where
neq q' x' = Match (q' /= x') q'
(-?>) :: Query Bool -> ManageHook -> MaybeManageHook
p -?> f = do
x <- p
if x then fmap Just f else return Nothing
(-->>) :: Query (Match a) -> (a -> ManageHook) -> ManageHook
p -->> f = do
Match b m <- p
if b then (f m) else mempty
(-?>>) :: Query (Match a) -> (a -> ManageHook) -> MaybeManageHook
p -?>> f = do
Match b m <- p
if b then fmap Just (f m) else return Nothing
currentWs :: Query WorkspaceId
currentWs = liftX (withWindowSet $ return . W.currentTag)
isKDETrayWindow :: Query Bool
isKDETrayWindow = ask >>= \w -> liftX $ do
r <- getProp32s "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR" w
return $ case r of
Just [_] -> True
_ -> False
isInProperty :: String -> String -> Query Bool
isInProperty p v = ask >>= \w -> liftX $ do
va <- getAtom v
r <- getProp32s p w
return $ case r of
Just xs -> fromIntegral va `elem` xs
_ -> False
isFullscreen :: Query Bool
isFullscreen = isInProperty "_NET_WM_STATE" "_NET_WM_STATE_FULLSCREEN"
isDialog :: Query Bool
isDialog = isInProperty "_NET_WM_WINDOW_TYPE" "_NET_WM_WINDOW_TYPE_DIALOG"
pid :: Query (Maybe ProcessID)
pid = ask >>= \w -> liftX $ do
p <- getProp32s "_NET_WM_PID" w
return $ case p of
Just [x] -> Just (fromIntegral x)
_ -> Nothing
transientTo :: Query (Maybe Window)
transientTo = do
w <- ask
d <- (liftX . asks) display
liftIO $ getTransientForHint d w
transience :: MaybeManageHook
transience = transientTo </=? Nothing -?>> move
where
move mw = maybe idHook (doF . move') mw
move' w s = maybe s (`W.shift` s) (W.findTag w s)
transience' :: ManageHook
transience' = maybeToDefinite transience
maybeToDefinite :: MaybeManageHook -> ManageHook
maybeToDefinite = fmap (fromMaybe mempty)
doRectFloat :: W.RationalRect
-> ManageHook
doRectFloat r = ask >>= \w -> doF (W.float w r)
doFullFloat :: ManageHook
doFullFloat = doRectFloat $ W.RationalRect 0 0 1 1
doFloatDep :: (W.RationalRect -> W.RationalRect) -> ManageHook
doFloatDep move = ask >>= \w -> doF . W.float w . move . snd =<< liftX (floatLocation w)
doFloatAt :: Rational -> Rational -> ManageHook
doFloatAt x y = doFloatDep move
where
move (W.RationalRect _ _ w h) = W.RationalRect x y w h
doSideFloat :: Side -> ManageHook
doSideFloat side = doFloatDep move
where
move (W.RationalRect _ _ w h) = W.RationalRect cx cy w h
where cx = if side `elem` [SC,C ,NC] then (1-w)/2
else if side `elem` [SW,CW,NW] then 0
else 1-w
cy = if side `elem` [CE,C ,CW] then (1-h)/2
else if side `elem` [NE,NC,NW] then 0
else 1-h
doCenterFloat :: ManageHook
doCenterFloat = doSideFloat C
doHideIgnore :: ManageHook
doHideIgnore = ask >>= \w -> liftX (hide w) >> doF (W.delete w)