aboutsummaryrefslogtreecommitdiffstats
path: root/TilePrime.hs
blob: 60a35a5c755a7747052915e65619485eeddcec67 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances #-}
-- --------------------------------------------------------------------------
-- -- |
-- -- Module      :  TilePrime.hs
-- -- Copyright   :  (c) Eric Mertens 2007
-- -- License     :  BSD3-style (see LICENSE)
-- --
-- -- Maintainer  :  emertens@gmail.com
-- -- Stability   :  unstable
-- -- Portability :  not portable
-- --
-- -- TilePrime. Tile windows filling gaps created by resize hints
-- --
-- -----------------------------------------------------------------------------
--

module XMonadContrib.TilePrime (
    -- * Usage
    -- $usage
    TilePrime(TilePrime)
    ) where

import Control.Monad (mplus)
import Data.List (mapAccumL)
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras (getWMNormalHints)
import Operations
import XMonad hiding (trace)
import qualified StackSet as W
import {-#SOURCE#-} Config (borderWidth)

-- $usage
-- You can use this module with the following in your Config.hs file:
--
-- > import XMonadContrib.TilePrime
--
-- and add the following line to your 'layouts'
--
-- > , Layout $ TilePrime nmaster delta ratio False
--
-- Use True as the last argument to get a wide layout.

-- %import XMonadContrib.TilePrime
-- %layout , Layout $ TilePrime nmaster delta ratio False

data TilePrime a = TilePrime
                         { nmaster     :: Int
                         , delta, frac :: Rational
                         , flipped     :: Bool
                         } deriving (Show, Read)

instance LayoutClass TilePrime Window where
  description c | flipped c = "TilePrime Horizontal"
                | otherwise = "TilePrime Vertical"

  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 }

  doLayout TilePrime { frac = f, nmaster = m, flipped = flp } rect s = do
    let xs = W.integrate s
    hints <- withDisplay $ \ disp -> io (mapM (getWMNormalHints disp) xs)
    let xs' = zip xs hints
        (leftRect, rightRect)
          | null (drop m xs) = (rect, Rectangle 0 0 0 0)
          | flp       = splitVerticallyBy f rect
          | otherwise = splitHorizontallyBy f rect
        (leftXs, rightXs) = splitAt m xs'
        masters = fillWindows leftRect leftXs
        slaves  = fillWindows rightRect rightXs
    return (masters ++ slaves, Nothing)

    where
    fillWindows r xs = snd $ mapAccumL aux (r,n) xs
      where n = fromIntegral (length xs) :: Rational

    aux (r,n) (x,hint) = ((rest,n-1),(x,r'))
      where
      (allocated, _) | flp       = splitHorizontallyBy (recip n) r
                     | otherwise = splitVerticallyBy (recip n) r

      (w,h) = applySizeHints hint `underBorders` rect_D allocated

      r'   = r { rect_width = w, rect_height = h }

      rest | flp       = r { rect_x      = rect_x r + toEnum (fromEnum w)
                           , rect_width  = rect_width r - w }
           | otherwise = r { rect_y      = rect_y r + toEnum (fromEnum h)
                           , rect_height = rect_height r - h }

rect_D :: Rectangle -> D
rect_D Rectangle { rect_width = w, rect_height = h } = (w,h)

-- | Transform a function on dimensions into one without regard for borders
underBorders :: (D -> D) -> D -> D
underBorders f = adjBorders 1 . f . adjBorders (-1)

-- | Modify dimensions by a multiple of the current borders
adjBorders             :: Dimension -> D -> D
adjBorders mult (w,h)  = (w+2*mult*borderWidth, h+2*mult*borderWidth)