about summary refs log tree commit diff
path: root/src/XMonad/Actions/FloatSnapSpaced.hs
blob: ad140163d3c9eecab99e179677a9868910ae8fb9 (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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
-- |
-- Module      : XMonad.Actions.FloatSnapSpaced
-- Copyright   : (c) 2009 Anders Engstrom <ankaan@gmail.com>
-- License     : BSD3-style (see LICENSE)
-- Maintainer  : Azat Bahawi <azahi@teknik.io>
-- Stability   : unstable
-- Portability : unportable
--

module XMonad.Actions.FloatSnapSpaced
  ( snapSpacedMagicMove
  ) where

import           Data.List
import           Data.Maybe
import           Data.Set                       ( fromList )
import           XMonad
import           XMonad.Hooks.ManageDocks
import qualified XMonad.StackSet               as S

snapSpacedMagicMove :: Int -> Maybe Int -> Maybe Int -> Window -> X ()
snapSpacedMagicMove spacing collidedist snapdist w =
  whenX (isClient w) $ withDisplay $ \d -> do
    io $ raiseWindow d w
    wa <- io $ getWindowAttributes d w

    nx <- handleAxis True d wa
    ny <- handleAxis False d wa

    io $ moveWindow d w (fromIntegral nx) (fromIntegral ny)
    float w
 where
  handleAxis horiz d wa = do
    ((mbl, mbr, bs), (mfl, mfr, fs)) <- getSnap horiz collidedist d w
    return $ if bs || fs
      then wpos wa
      else
        let
          b = case (mbl, mbr) of
            (Just bl, Just br) ->
              if wpos wa - bl < br - wpos wa then bl + spacing else br + spacing
            (Just bl, Nothing) -> bl + spacing
            (Nothing, Just br) -> br + spacing
            (Nothing, Nothing) -> wpos wa + spacing

          f = case (mfl, mfr) of
            (Just fl, Just fr) ->
              if wpos wa + wdim wa - fl < fr - wpos wa - wdim wa
                then fl - spacing
                else fr - spacing
            (Just fl, Nothing) -> fl - spacing
            (Nothing, Just fr) -> fr - spacing
            (Nothing, Nothing) -> wpos wa - spacing

          newpos = if abs (b - wpos wa) <= abs (f - wpos wa - wdim wa)
            then b
            else f - wdim wa
        in
          if isNothing snapdist || abs (newpos - wpos wa) <= fromJust snapdist
            then newpos
            else wpos wa
    where (wpos, wdim, _, _) = constructors horiz

getSnap
  :: Bool
  -> Maybe Int
  -> Display
  -> Window
  -> X ((Maybe Int, Maybe Int, Bool), (Maybe Int, Maybe Int, Bool))
getSnap horiz collidedist d w = do
  wa     <- io $ getWindowAttributes d w
  screen <- S.current <$> gets windowset
  let sr = screenRect $ S.screenDetail screen
      wl = S.integrate' . S.stack $ S.workspace screen
  gr  <- fmap ($ sr) $ calcGap $ fromList [minBound .. maxBound]
  wla <- filter (collides wa)
    <$> io (mapM (getWindowAttributes d) $ filter (/= w) wl)

  return
    ( neighbours (back wa sr gr wla)  (wpos wa)
    , neighbours (front wa sr gr wla) (wpos wa + wdim wa)
    )
 where
  wborder                        = fromIntegral . wa_border_width

  (wpos   , wdim   , rpos, rdim) = constructors horiz
  (refwpos, refwdim, _   , _   ) = constructors $ not horiz

  back wa sr gr wla =
    dropWhile (< rpos sr)
      $ takeWhile (< rpos sr + rdim sr)
      $ sort
      $ rpos sr
      : rpos gr
      : (rpos gr + rdim gr)
      : foldr
          (\a as -> wpos a : (wpos a + wdim a + wborder a + wborder wa) : as)
          []
          wla

  front wa sr gr wla =
    dropWhile (<= rpos sr)
      $ takeWhile (<= rpos sr + rdim sr)
      $ sort
      $ (rpos gr - 2 * wborder wa)
      : (rpos gr + rdim gr - 2 * wborder wa)
      : (rpos sr + rdim sr - 2 * wborder wa)
      : foldr
          (\a as -> (wpos a - wborder a - wborder wa) : (wpos a + wdim a) : as)
          []
          wla

  neighbours l v =
    ( listToMaybe $ reverse $ takeWhile (< v) l
    , listToMaybe $ dropWhile (<= v) l
    , v `elem` l
    )

  collides wa oa = case collidedist of
    Nothing -> True
    Just dist ->
      refwpos oa
        -  wborder oa
        <  refwpos wa
        +  refwdim wa
        +  wborder wa
        +  dist
        && refwpos wa
        -  wborder wa
        -  dist
        <  refwpos oa
        +  refwdim oa
        +  wborder oa


constructors
  :: Bool
  -> ( WindowAttributes -> Int
     , WindowAttributes -> Int
     , Rectangle -> Int
     , Rectangle -> Int
     )
constructors True =
  ( fromIntegral . wa_x
  , fromIntegral . wa_width
  , fromIntegral . rect_x
  , fromIntegral . rect_width
  )
constructors False =
  ( fromIntegral . wa_y
  , fromIntegral . wa_height
  , fromIntegral . rect_y
  , fromIntegral . rect_height
  )

Consider giving Nix/NixOS a try! <3