{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, DeriveDataTypeable #-} ----------------------------------------------------------------------------- -- | -- Module : XMonad.Layout.MessageControl -- Copyright : (c) 2008 Quentin Moser -- License : BSD3 -- -- Maintainer : orphaned -- Stability : unstable -- Portability : unportable -- -- Provides message \"escaping\" and filtering facilities which -- help control complex nested layouts. ----------------------------------------------------------------------------- module XMonad.Layout.MessageControl ( -- * Usage -- $usage Ignore() , ignore , UnEscape() , unEscape , EscapedMessage(Escape) , escape ) where import XMonad.Core (Message, SomeMessage(..) , fromMessage, LayoutClass(..)) import XMonad.StackSet (Workspace(..)) import XMonad.Layout.LayoutModifier (LayoutModifier(..), ModifiedLayout(..)) import Data.Typeable (Typeable) import Control.Applicative ((<$>)) import Control.Arrow (second) -- $usage -- You can use this module by importing it into your @~\/.xmonad\/xmonad.hs@ file: -- -- > import XMonad.Layout.MessageEscape -- -- Then, if you use a modified layout where the modifier would intercept -- a message, but you'd want to be able to send it to the inner layout -- only, add the 'unEscape' modifier to the inner layout like so: -- -- > import XMonad.Layout.Master (mastered) -- > import XMonad.Layout.Tabbed (simpleTabbed) -- > import XMonad.Layout.LayoutCombinators ((|||)) -- > -- > myLayout = Tall ||| unEscape (mastered 0.01 0.5 $ Full ||| simpleTabbed) -- -- you can now send a message to the inner layout with -- @sendMessage $ escape message@, e.g. -- -- > -- Change the inner layout -- > ((modm .|. controlMask, xK_space), sendMessage $ escape NextLayout) -- -- If you want unescaped messages to be handled /only/ by the enclosing -- layout, use the 'ignore' modifier: -- -- > myLayout = Tall ||| (ignore NextLayout $ ignore (JumpToLayout "") $ -- > unEscape $ mastered 0.01 0.5 -- > $ Full ||| simpleTabbed) -- -- /IMPORTANT NOTE:/ The standard '(|||)' operator from "XMonad.Layout" -- does not behave correctly with 'ignore'. Make sure you use the one -- from "XMonad.Layout.LayoutCombinators". -- | the Ignore layout modifier. Prevents its inner layout from receiving -- messages of a certain type. data Ignore m l w = I (l w) deriving (Show, Read) instance (Message m, LayoutClass l w) => LayoutClass (Ignore m l) w where runLayout ws r = second (I <$>) <$> runLayout (unILayout ws) r where unILayout :: Workspace i (Ignore m l w) w -> Workspace i (l w) w unILayout w@(Workspace { layout = (I l) }) = w { layout = l } handleMessage l@(I l') sm = case fromMessageAs sm l of Just _ -> return Nothing Nothing -> (I <$>) <$> handleMessage l' sm where fromMessageAs :: Message m' => SomeMessage -> Ignore m' l w -> Maybe m' fromMessageAs a _ = fromMessage a description (I l) = "Ignore "++description l -- | the UnEscape layout modifier. Listens to 'EscapedMessage's and sends -- their nested message to the inner layout. data UnEscape w = UE deriving (Show, Read) instance LayoutModifier UnEscape a where handleMessOrMaybeModifyIt _ mess = return $ case fromMessage mess of Just (Escape mess') -> Just $ Right mess' Nothing -> Nothing -- | Data type for an escaped message. Send with 'escape'. newtype EscapedMessage = Escape SomeMessage deriving Typeable instance Message EscapedMessage -- | Creates an 'EscapedMessage'. escape :: Message m => m -> EscapedMessage escape = Escape . SomeMessage -- | Applies the UnEscape layout modifier to a layout. unEscape :: LayoutClass l w => l w -> ModifiedLayout UnEscape l w unEscape l = ModifiedLayout UE l -- | Applies the Ignore layout modifier to a layout, blocking -- all messages of the same type as the one passed as its first argument. ignore :: (Message m, LayoutClass l w) => m -> l w -> (Ignore m l w) ignore _ l = I l