module Rahm.Desktop.Layout.Layout where import GHC.TypeLits import Data.Proxy (Proxy(..)) import Control.Arrow (second) import XMonad.Hooks.ManageDocks import XMonad.Layout.Circle import XMonad.Layout.Accordion import Control.Applicative import XMonad.Layout.Spacing import Data.List import XMonad.Layout.Spiral import XMonad.Layout.ThreeColumns import XMonad.Layout.Grid import XMonad.Layout.Dishes import XMonad.Layout.MosaicAlt import XMonad.Layout.Fullscreen import qualified XMonad.Layout.Dwindle as D import XMonad.Layout import XMonad.Layout.LayoutModifier import XMonad import XMonad.Core import XMonad.Layout.NoBorders (smartBorders, noBorders) import Rahm.Desktop.Layout.CornerLayout (Corner(..)) import Rahm.Desktop.Layout.LayoutList import Rahm.Desktop.Windows import Rahm.Desktop.Layout.ReinterpretMessage import Rahm.Desktop.Layout.Pop import Rahm.Desktop.Layout.Flip import qualified Data.Map as M import qualified XMonad.StackSet as W myLayout = fullscreenFull $ avoidStruts $ spacingRaw True (Border 5 5 5 5) True (Border 5 5 5 5) True $ layoutZipper $ mods (reinterpretIncMaster $ spiral (6/7)) |: mods (modifyMosaic (MosaicAlt M.empty :: MosaicAlt Window)) |: mods (reinterpretIncMaster $ Corner (3/4) (3/100)) |: mods (ModifyDescription TallDescriptionModifier (Tall 1 (3/100) (1/2))) |: mods (ModifyDescription ThreeColDescMod (ThreeCol 1 (3/100) (1/2))) |: mods Grid |: mods (Dishes 2 (1/6)) |: mods (reinterpretIncMaster $ D.Dwindle D.R D.CW 1.5 1.1) |: nil -- Mosaic doesn't have the concept of a "Master Space", so reinterpret messages -- intended to modify the master space and instead have those messages expand -- and shrink the current window. -- -- "ForMosaic" is an instance of the Symbol kind. This is some neat type-system -- hacking one can do in Haskell. instance DoReinterpret "ForMosaic" where -- IncMaster message reinterpretMessage _ (fromMessage -> Just (IncMasterN n)) = do fmap (SomeMessage . (if n > 0 then expandWindowAlt else shrinkWindowAlt)) <$> getFocusedWindow -- ResizeMaster message reinterpretMessage _ (fromMessage -> Just m) = do fmap (SomeMessage . (case m of Expand -> expandWindowAlt Shrink -> shrinkWindowAlt)) <$> getFocusedWindow -- Messages that don't match the above, just leave it unmodified. reinterpretMessage _ m = return (Just m) instance DoReinterpret "IncMasterToResizeMaster" where reinterpretMessage _ (fromMessage -> Just (IncMasterN n)) = return $ Just $ if n > 0 then SomeMessage Expand else SomeMessage Shrink reinterpretMessage _ m = return (Just m) modifyMosaic :: l a -> ModifiedLayout (ReinterpretMessage "ForMosaic") l a modifyMosaic = ModifiedLayout ReinterpretMessage reinterpretIncMaster :: l a -> ModifiedLayout (ReinterpretMessage "IncMasterToResizeMaster") l a reinterpretIncMaster = ModifiedLayout ReinterpretMessage mods = reinterpretResize . poppable . flippable . ModifiedLayout (Rotateable False) data ModifyDescription m l a = ModifyDescription m (l a) deriving (Show, Read) data TallDescriptionModifier = TallDescriptionModifier deriving (Show, Read) data ThreeColDescMod = ThreeColDescMod deriving (Show, Read) class DescriptionModifier m l where newDescription :: m -> l a -> String -> String instance (Typeable m, Show m, DescriptionModifier m l, LayoutClass l a) => LayoutClass (ModifyDescription m l) a where runLayout (W.Workspace t (ModifyDescription m l) a) rect = do (rects, maybeNewLayout) <- runLayout (W.Workspace t l a) rect return (rects, fmap (ModifyDescription m) maybeNewLayout) doLayout (ModifyDescription m l) a s = do (rects, maybeNewLayout) <- doLayout l a s return (rects, fmap (ModifyDescription m) maybeNewLayout) pureLayout (ModifyDescription m l) a s = pureLayout l a s emptyLayout (ModifyDescription m l) a = do (rects, maybeNewLayout) <- emptyLayout l a return (rects, fmap (ModifyDescription m) maybeNewLayout) handleMessage (ModifyDescription m l) a = do maybeNewLayout <- handleMessage l a return (ModifyDescription m <$> maybeNewLayout) pureMessage (ModifyDescription m l) a = let maybeNewLayout = pureMessage l a in ModifyDescription m <$> maybeNewLayout description (ModifyDescription m l) = newDescription m l (description l) instance DescriptionModifier TallDescriptionModifier Tall where newDescription _ (Tall mast _ _) _ = "Tall(" ++ show mast ++ ")" instance DescriptionModifier ThreeColDescMod ThreeCol where newDescription _ (ThreeCol mast _ _) _ = "ThreeCol(" ++ show mast ++ ")" newDescription _ (ThreeColMid mast _ _) _ = "ThreeColMid(" ++ show mast ++ ")" newtype Rotateable a = Rotateable Bool -- True if rotated deriving (Show, Read) data DoRotate = DoRotate deriving (Typeable) instance Message DoRotate where instance (Eq a) => LayoutModifier Rotateable a where pureModifier (Rotateable rotate) (Rectangle x' y' sw sh) _ returned = if rotate then (map (second (unzero . scaleRect . mirrorRect . zero)) returned, Nothing) else (returned, Nothing) where zero (Rectangle x y w h) = Rectangle (x - x') (y - y') w h unzero (Rectangle x y w h) = Rectangle (x + x') (y + y') w h scaleRect (Rectangle x y w h) = Rectangle (x * fi sw `div` fi sh) (y * fi sh `div` fi sw) (w * sw `div` sh) (h * sh `div` sw) fi = fromIntegral pureMess (Rotateable rot) mess = fmap (\DoRotate -> Rotateable (not rot)) (fromMessage mess) modifyDescription (Rotateable rot) underlying = let descr = description underlying in if rot then descr ++ " Rotated" else descr