{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances #-} ----------------------------------------------------------------------------- -- | -- Module : XMonad.Layout.HintedTile -- Copyright : (c) Peter De Wachter -- License : BSD3-style (see LICENSE) -- -- Maintainer : Peter De Wachter -- Andrea Rossato -- Stability : unstable -- Portability : unportable -- -- A gapless tiled layout that attempts to obey window size hints, -- rather than simply ignoring them. -- ----------------------------------------------------------------------------- module XMonad.Layout.HintedTile ( -- * Usage -- $usage HintedTile(..), Orientation(..), Alignment(..) ) where import XMonad hiding (Tall(..)) import qualified XMonad.StackSet as W import Control.Monad -- $usage -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@: -- -- > import XMonad.Layout.HintedTile -- -- Then edit your @layoutHook@ by adding the HintedTile layout: -- -- > myLayout = hintedTile Tall ||| hintedTile Wide ||| Full ||| etc.. -- > where -- > hintedTile = HintedTile nmaster delta ratio TopLeft -- > nmaster = 1 -- > ratio = 1/2 -- > delta = 3/100 -- > main = xmonad defaultConfig { layoutHook = myLayout } -- -- Because both Xmonad and Xmonad.Layout.HintedTile define Tall, -- you need to disambiguate Tall. If you are replacing the -- built-in Tall with HintedTile, change @import Xmonad@ to -- @import Xmonad hiding (Tall)@. -- -- For more detailed instructions on editing the layoutHook see: -- -- "XMonad.Doc.Extending#Editing_the_layout_hook" data HintedTile a = HintedTile { nmaster :: !Int -- ^ number of windows in the master pane , delta :: !Rational -- ^ how much to change when resizing , frac :: !Rational -- ^ ratio between master/nonmaster panes , alignment :: !Alignment -- ^ Where to place windows that are smaller -- than their preordained rectangles. , orientation :: !Orientation -- ^ Tall or Wide (mirrored) layout? } deriving ( Show, Read ) data Orientation = Wide -- ^ Lay out windows similarly to Mirror tiled. | Tall -- ^ Lay out windows similarly to tiled. deriving ( Show, Read, Eq, Ord ) data Alignment = TopLeft | Center | BottomRight deriving ( Show, Read, Eq, Ord ) instance LayoutClass HintedTile Window where doLayout (HintedTile { orientation = o, nmaster = nm, frac = f, alignment = al }) r w' = do bhs <- mapM mkAdjust w let (masters, slaves) = splitAt nm bhs return (zip w (tiler masters slaves), Nothing) where w = W.integrate w' tiler masters slaves | null masters || null slaves = divide al o (masters ++ slaves) r | otherwise = split o f r (divide al o masters) (divide al o slaves) pureMessage c m = fmap resize (fromMessage m) `mplus` fmap incmastern (fromMessage m) where resize Shrink = c { frac = max 0 $ frac c - delta c } resize Expand = c { frac = min 1 $ frac c + delta c } incmastern (IncMasterN d) = c { nmaster = max 0 $ nmaster c + d } description l = show (orientation l) align :: Alignment -> Position -> Dimension -> Dimension -> Position align TopLeft p _ _ = p align Center p a b = p + fromIntegral (a - b) `div` 2 align BottomRight p a b = p + fromIntegral (a - b) -- Divide the screen vertically (horizontally) into n subrectangles divide :: Alignment -> Orientation -> [D -> D] -> Rectangle -> [Rectangle] divide _ _ [] _ = [] divide al _ [bh] (Rectangle sx sy sw sh) = [Rectangle (align al sx sw w) (align al sy sh h) w h] where (w, h) = bh (sw, sh) divide al Tall (bh:bhs) (Rectangle sx sy sw sh) = (Rectangle (align al sx sw w) sy w h) : (divide al Tall bhs (Rectangle sx (sy + fromIntegral h) sw (sh - h))) where (w, h) = bh (sw, sh `div` fromIntegral (1 + (length bhs))) divide al Wide (bh:bhs) (Rectangle sx sy sw sh) = (Rectangle sx (align al sy sh h) w h) : (divide al Wide bhs (Rectangle (sx + fromIntegral w) sy (sw - w) sh)) where (w, h) = bh (sw `div` fromIntegral (1 + (length bhs)), sh) -- Split the screen into two rectangles, using a rational to specify the ratio split :: Orientation -> Rational -> Rectangle -> (Rectangle -> [Rectangle]) -> (Rectangle -> [Rectangle]) -> [Rectangle] split Tall f (Rectangle sx sy sw sh) left right = leftRects ++ rightRects where leftw = floor $ fromIntegral sw * f leftRects = left $ Rectangle sx sy leftw sh rightx = (maximum . map rect_width) leftRects rightRects = right $ Rectangle (sx + fromIntegral rightx) sy (sw - rightx) sh split Wide f (Rectangle sx sy sw sh) top bottom = topRects ++ bottomRects where toph = floor $ fromIntegral sh * f topRects = top $ Rectangle sx sy sw toph bottomy = (maximum . map rect_height) topRects bottomRects = bottom $ Rectangle sx (sy + fromIntegral bottomy) sw (sh - bottomy)