xmonad-contrib-0.18.2: tests/WindowNavigation.hs
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module WindowNavigation where
import Test.Hspec
import qualified Data.Map as M
import qualified Data.Set as S
import Data.Functor.Identity
import XMonad
import XMonad.Util.Types (Direction2D(..))
import XMonad.Actions.WindowNavigation (goPure, swapPure, WNState)
import qualified XMonad.StackSet as W
spec :: Spec
spec = do
it "two-window adjacent go right (empty state)" $ do
-- Simplest case - just move the focus once.
-- ┌─────┬──────┐
-- │ 1 ──┼─► 2 │
-- └─────┴──────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 1280)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1, 2], windowRect)
runNav R M.empty (mkws 1 [] [2])
`shouldBe` (mkstate 960 640, mkws 2 [1] [])
it "two-window adjacent go right (populated state)" $ do
-- Like the previous test, but this time internal stat is already populated with a position.
-- ┌─────┬──────┐
-- │ 1 ──┼─► 2 │
-- └─────┴──────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 1280)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1, 2], windowRect)
runNav R (mkstate 100 100) (mkws 1 [] [2])
`shouldBe` (mkstate 960 100, mkws 2 [1] [])
it "two-window adjacent go right (incorrectly-populated state)" $ do
-- This time we set the position incorrectly, testing if it will be reset to the center of focused window.
-- ┌─────┬──────┐
-- │ 1 ──┼─► 2 │
-- └─────┴──────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 1280)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1, 2], windowRect)
runNav R (mkstate 1000 100) (mkws 1 [] [2])
`shouldBe` (mkstate 960 640, mkws 2 [1] [])
it "swap windows" $ do
-- Swap windows around.
-- ┌─────┬──────┐
-- │ 1 ◄─┼─► 2 │
-- └─────┴──────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 1280)
]
runIdentity (swapPure R (M.empty, mkws 1 [] [2], S.fromList [1, 2], windowRect))
`shouldBe` (mkstate 960 640, mkws 1 [2] [])
it "tall layout, go up" $ do
-- ┌─────┬─────┐
-- │ │ 2 ▲ │
-- │ 1 ├───┼─┤
-- │ │ 3 │ │
-- └─────┴─────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 640)
, (3, Rectangle 960 640 960 640)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1, 2, 3], windowRect)
runNav U M.empty (mkws 3 [] [1, 2])
`shouldBe` (mkstate 1440 639, mkws 2 [1, 3] [])
it "tall layout, go down" $ do
-- ┌─────┬─────┐
-- │ │ 2 │
-- │ ├─────┤
-- │ 1 │ 3 │ │
-- │ ├───┼─┤
-- │ │ 4 ▼ │
-- └─────┴─────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 400)
, (3, Rectangle 960 400 960 400)
, (4, Rectangle 960 800 960 480)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..4], windowRect)
runNav D M.empty (mkws 3 [] [1, 2, 4])
`shouldBe` (mkstate 1440 800, mkws 4 [2, 1, 3] [])
it "tall layout, go left" $ do
-- ┌─────┬─────┐
-- │ ◄─┼── 2 │
-- │ ├─────┤
-- │ 1 │ 3 │
-- │ ├─────┤
-- │ │ 4 │
-- └─────┴─────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 400)
, (3, Rectangle 960 400 960 400)
, (4, Rectangle 960 800 960 480)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..4], windowRect)
runNav L M.empty (mkws 2 [] [1, 3, 4])
`shouldBe` (mkstate 959 200, mkws 1 [2] [3, 4])
it "tall layout, go left and then right (window 2)" $ do
-- ┌─────┬─────┐
-- │ ◄─┼── 2 │
-- │ ──┼─► │
-- │ ├─────┤
-- │ 1 │ 3 │
-- │ ├─────┤
-- │ │ 4 │
-- └─────┴─────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 400)
, (3, Rectangle 960 400 960 400)
, (4, Rectangle 960 800 960 480)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..4], windowRect)
let (st2, ws2) = runNav L M.empty (mkws 2 [] [1, 3, 4])
(st2, ws2) `shouldBe` (mkstate 959 200, mkws 1 [2] [3, 4])
let (st3, ws3) = runNav R st2 ws2
(st3, ws3) `shouldBe` (mkstate 960 200, mkws 2 [] [1, 3, 4])
it "tall layout, go left and then right (window 3)" $ do
-- ┌─────┬─────┐
-- │ │ 2 │
-- │ ├─────┤
-- │ 1 ◄─┼── 3 │
-- │ ──┼─► │
-- │ ├─────┤
-- │ │ 4 │
-- └─────┴─────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 400)
, (3, Rectangle 960 400 960 400)
, (4, Rectangle 960 800 960 480)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..4], windowRect)
let (st2, ws2) = runNav L M.empty (mkws 3 [] [1, 2, 4])
(st2, ws2) `shouldBe` (mkstate 959 600, mkws 1 [3] [2, 4])
let (st3, ws3) = runNav R st2 ws2
(st3, ws3) `shouldBe` (mkstate 960 600, mkws 3 [] [1, 2, 4])
it "tall layout, go left and then right (window 4)" $ do
-- ┌─────┬─────┐
-- │ │ 2 │
-- │ ├─────┤
-- │ 1 │ 3 │
-- │ ├─────┤
-- │ ◄─┼── 4 │
-- │ ──┼─► │
-- └─────┴─────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 400)
, (3, Rectangle 960 400 960 400)
, (4, Rectangle 960 800 960 480)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..4], windowRect)
let (st2, ws2) = runNav L M.empty (mkws 4 [] [1, 2, 3])
(st2, ws2) `shouldBe` (mkstate 959 1040, mkws 1 [4] [2, 3])
let (st3, ws3) = runNav R st2 ws2
(st3, ws3) `shouldBe` (mkstate 960 1040, mkws 4 [] [1, 2, 3])
it "grid layout, go in a circle" $ do
-- ┌─────┬─────┐
-- │ 1 ──┼─► 2 │
-- │ │ │
-- │ ▲ │ │ │
-- ├─┼───┼───┼─┤
-- │ │ │ ▼ │
-- │ │ │
-- │ 3 ◄─┼── 4 │
-- └─────┴─────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 640)
, (2, Rectangle 960 0 960 640)
, (3, Rectangle 0 640 960 640)
, (4, Rectangle 960 640 960 640)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..4], windowRect)
let (st2, ws2) = runNav R M.empty (mkws 1 [] [2, 3, 4])
(st2, ws2) `shouldBe` (mkstate 960 320, mkws 2 [1] [3, 4])
let (st3, ws3) = runNav D st2 ws2
(st3, ws3) `shouldBe` (mkstate 960 640, mkws 4 [3, 2, 1] [])
let (st4, ws4) = runNav L st3 ws3
(st4, ws4) `shouldBe` (mkstate 959 640, mkws 3 [2, 1] [4])
let (st5, ws5) = runNav U st4 ws4
(st5, ws5) `shouldBe` (mkstate 959 639, mkws 1 [] [2, 3, 4])
it "ignore window that fully overlaps the current window in parallel direction when pos is outside it" $ do
-- ┌─────┬──────┬──────┐
-- │ ┌───┴──────┴────┐ │
-- │ │ | 4 | │ │
-- │ └───┬──────┬────┘ │
-- │ 1 │ 2 ──┼─► 3 │
-- └─────┴──────┴──────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 600 1280)
, (2, Rectangle 600 0 600 1280)
, (3, Rectangle 1200 0 720 1280)
, (4, Rectangle 200 200 1520 400)
]
runIdentity (goPure R (mkstate 900 900, mkws 2 [] [1, 3, 4], S.fromList [1..4], windowRect))
`shouldBe` (mkstate 1200 900, mkws 3 [1,2] [4])
it "go to window that fully overlaps the current window in parallel direction when pos is inside it" $ do
-- ┌─────────────────┐
-- │ ┌──────┐ │
-- │ 1 │ │ │
-- ├─────┤------├────┤
-- │ │ │ │
-- │ 2 │ 4 ──┼─► │
-- │ │ │ │
-- ├─────┤------├────┤
-- │ 3 │ │ │
-- │ └──────┘ │
-- └─────────────────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 1920 400)
, (2, Rectangle 0 400 1920 400)
, (3, Rectangle 0 800 1920 480)
, (4, Rectangle 800 200 400 880)
]
runIdentity (goPure R (mkstate 1000 600, mkws 4 [] [1, 2, 3], S.fromList [1..4], windowRect))
`shouldBe` (mkstate 1200 600, mkws 2 [1,4] [3])
it "go from inner window to outer" $ do
-- ┌───────────────┐
-- │ ┌──────┐ │
-- │ 1 ◄─┼── 2 │ │
-- │ └──────┘ │
-- └───────────────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 1920 1280)
, (2, Rectangle 600 600 600 600)
]
runIdentity (goPure L (M.empty, mkws 2 [] [1], S.fromList [1, 2], windowRect))
`shouldBe` (mkstate 599 900, mkws 1 [2] [])
it "if there are multiple outer windows, go to the smaller one" $ do
-- ┌────────────────────────┐
-- │ ┌───────────────┐ │
-- │ │ ┌──────┐ │ │
-- │ │ 2 ◄─┼── 3 │ │ 1 │
-- │ │ └──────┘ │ │
-- │ └───────────────┘ │
-- └────────────────────────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 1920 1280)
, (2, Rectangle 200 200 1520 880)
, (3, Rectangle 400 400 400 400)
]
runIdentity (goPure L (M.empty, mkws 3 [] [1, 2], S.fromList [1..3], windowRect))
`shouldBe` (mkstate 399 600, mkws 2 [1, 3] [])
it "two tiled and one floating, floating fully inside" $ do
-- ┌───────────────────┬─────┐
-- │ ┌───────┐ │ │
-- │ ──┼─► ──┼─► ──┼─► │
-- │ │ 3 │ 1 │ 2 │
-- │ │ ◄─┼── ◄─┼── │
-- │ └───────┘ │ │
-- └───────────────────┴─────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 1280)
, (3, Rectangle 400 400 400 400)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..3], windowRect)
let (st2, ws2) = runNav R (mkstate 100 100) (mkws 1 [] [2, 3])
(st2, ws2) `shouldBe` (mkstate 400 400, mkws 3 [2, 1] [])
let (st3, ws3) = runNav R st2 ws2
(st3, ws3) `shouldBe` (mkstate 800 400, mkws 1 [] [2, 3])
let (st4, ws4) = runNav R st3 ws3
(st4, ws4) `shouldBe` (mkstate 960 400, mkws 2 [1] [3])
let (st5, ws5) = runNav L st4 ws4
(st5, ws5) `shouldBe` (mkstate 959 400, mkws 1 [] [2, 3])
let (st6, ws6) = runNav L st5 ws5
(st6, ws6) `shouldBe` (mkstate 799 400, mkws 3 [2, 1] [])
it "two floating windows inside one big tiled one" $ do
-- ┌─────────┐
-- │ │ │
-- │ ┌──┼──┐ │
-- │ │ ▼ │ │
-- │ │ 3 │ │
-- │ └──┼──┘ │
-- │ ▼ │
-- │ 1 │
-- │ ┌──┼──┐ │
-- │ │ ▼ │ │
-- │ │ 4 │ │
-- │ └──┼──┘ │
-- │ ▼ │
-- ├────┼────┤
-- │ ▼ │
-- │ 2 │
-- └─────────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 1920 640)
, (2, Rectangle 0 640 1920 640)
, (3, Rectangle 200 200 100 100)
, (4, Rectangle 1000 400 100 100)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..4], windowRect)
let (st2, ws2) = runNav D (mkstate 1000 250) (mkws 1 [] [2, 3, 4])
(st2, ws2) `shouldBe` (mkstate 299 250, mkws 3 [2, 1] [4])
let (st3, ws3) = runNav D st2 ws2
(st3, ws3) `shouldBe` (mkstate 299 300, mkws 1 [] [2, 3, 4])
let (st4, ws4) = runNav D st3 ws3
(st4, ws4) `shouldBe` (mkstate 1000 400, mkws 4 [3, 2, 1] [])
let (st5, ws5) = runNav D st4 ws4
(st5, ws5) `shouldBe` (mkstate 1000 500, mkws 1 [] [2, 3, 4])
let (st6, ws6) = runNav D st5 ws5
(st6, ws6) `shouldBe` (mkstate 1000 640, mkws 2 [1] [3, 4])
it "floating window between two tiled ones" $ do
-- ┌───────┬────────┐
-- │ 1 ┌───┴───┐ 2 │
-- │ ──┼─► 3 ──┼─► │
-- │ └───┬───┘ │
-- └───────┴────────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 1280)
, (3, Rectangle 860 540 200 200)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..3], windowRect)
let (st2, ws2) = runNav R M.empty (mkws 1 [] [2, 3])
(st2, ws2) `shouldBe` (mkstate 860 640, mkws 3 [2, 1] [])
let (st3, ws3) = runNav R st2 ws2
(st3, ws3) `shouldBe` (mkstate 960 640, mkws 2 [1] [3])
it "floating window overlapping four tiled ones" $ do
-- ┌───────┬───────┐
-- │ ┌───┴───┐ │
-- │ 1 │ │ 2 │
-- ├───┤ ├───┤
-- │ ──┼─► 5 ──┼─► │
-- │ 3 └───┬───┘ 4 │
-- └───────┴───────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 640)
, (2, Rectangle 960 0 960 640)
, (3, Rectangle 0 640 960 640)
, (4, Rectangle 960 640 960 640)
, (5, Rectangle 760 440 400 400)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..5], windowRect)
let (st2, ws2) = runNav R (mkstate 480 640) (mkws 3 [] [1, 2, 4, 5])
(st2, ws2) `shouldBe` (mkstate 760 640, mkws 5 [4, 2, 1, 3] [])
let (st3, ws3) = runNav R st2 ws2
(st3, ws3) `shouldBe` (mkstate 960 640, mkws 4 [2, 1, 3] [5])
it "sequential inner floating windows" $ do
-- ┌───────────────────────────────────┬──────┐
-- │ ┌───────┐ │ │
-- │ │ │ ┌───────┐ │ │
-- │ ──┼─► 3 ──┼─► 1 ──┼─► 4 ──┼─► ──┼─► 2 │
-- │ ◄─┼── ◄─┼── ◄─┼── ◄─┼── ◄─┼── │
-- │ └───────┘ │ │ │ │
-- │ └───────┘ │ │
-- └───────────────────────────────────┴──────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 1280)
, (3, Rectangle 200 200 200 200)
, (4, Rectangle 600 600 200 200)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..4], windowRect)
let (st2, ws2) = runNav R (mkstate 100 100) (mkws 1 [] [2, 3, 4])
(st2, ws2) `shouldBe` (mkstate 200 200, mkws 3 [2,1] [4])
let (st3, ws3) = runNav R st2 ws2
(st3, ws3) `shouldBe` (mkstate 400 200, mkws 1 [] [2, 3, 4])
let (st4, ws4) = runNav R st3 ws3
(st4, ws4) `shouldBe` (mkstate 600 600, mkws 4 [3, 2, 1] [])
let (st5, ws5) = runNav R st4 ws4
(st5, ws5) `shouldBe` (mkstate 800 600, mkws 1 [] [2, 3, 4])
let (st6, ws6) = runNav R st5 ws5
(st6, ws6) `shouldBe` (mkstate 960 600, mkws 2 [1] [3, 4])
let (st7, ws7) = runNav L st6 ws6
(st7, ws7) `shouldBe` (mkstate 959 600, mkws 1 [] [2, 3, 4])
let (st8, ws8) = runNav L st7 ws7
(st8, ws8) `shouldBe` (mkstate 799 600, mkws 4 [3, 2, 1] [])
let (st9, ws9) = runNav L st8 ws8
(st9, ws9) `shouldBe` (mkstate 599 600, mkws 1 [] [2, 3, 4])
let (st10, ws10) = runNav L st9 ws9
(st10, ws10) `shouldBe` (mkstate 399 399, mkws 3 [2, 1] [4])
let (st11, ws11) = runNav L st10 ws10
(st11, ws11) `shouldBe` (mkstate 199 399, mkws 1 [] [2, 3, 4])
it "overlapping inner floating windows" $ do
-- ┌─────────────────────┬──────┐
-- │ ┌─────────┐ │ │
-- │ │ 3 ┌────┴─┐ │ │
-- │ │ ──┼─► ──┼─► 1 ──┼─► 2 │
-- │ │ ◄─┼── ◄─┼── ◄─┼── │
-- │ │ │ 4 │ │ │
-- │ └────┤ │ │ │
-- │ └──────┘ │ │
-- └─────────────────────┴──────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 1280)
, (3, Rectangle 200 200 400 400)
, (4, Rectangle 300 300 400 400)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..4], windowRect)
let (st2, ws2) = runNav R M.empty (mkws 3 [] [1, 2, 4])
(st2, ws2) `shouldBe` (mkstate 400 400, mkws 4 [2, 1, 3] [])
let (st3, ws3) = runNav R st2 ws2
(st3, ws3) `shouldBe` (mkstate 700 400, mkws 1 [3] [2, 4])
let (st4, ws4) = runNav R st3 ws3
(st4, ws4) `shouldBe` (mkstate 960 400, mkws 2 [1, 3] [4])
let (st5, ws5) = runNav L st4 ws4
(st5, ws5) `shouldBe` (mkstate 959 400, mkws 1 [3] [2, 4])
let (st6, ws6) = runNav L st5 ws5
(st6, ws6) `shouldBe` (mkstate 699 400, mkws 4 [2, 1, 3] [])
let (st7, ws7) = runNav L st6 ws6
(st7, ws7) `shouldBe` (mkstate 599 400, mkws 3 [] [1, 2, 4])
it "bounce back from the wall to the floating window" $ do
-- ┌────────────────┬─────┐
-- │ 1 ┌──────┐ │ │
-- │ ┌───┼─► 3 │ │ 2 │
-- │ └── │ │ │ │
-- │ └──────┘ │ │
-- └────────────────┴─────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 1280)
, (3, Rectangle 400 400 200 200)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..3], windowRect)
runNav L (mkstate 100 640) (mkws 1 [] [2, 3])
`shouldBe` (mkstate 400 599, mkws 3 [2, 1] [])
it "jump between screens" $ do
-- ┌─────┬──────┐ ┌────────┐
-- │ │ 2 │ │ 5 │
-- │ ├──────┤ ├────────┤
-- │ 1 │ 3 ──┼──┼─► 6 │
-- │ ├──────┤ └────────┘
-- │ │ 4 │
-- └─────┴──────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 400)
, (3, Rectangle 960 400 960 400)
, (4, Rectangle 960 800 960 480)
, (5, Rectangle 1920 0 1280 384)
, (6, Rectangle 1920 384 1280 384)
]
initWindowSet =
W.StackSet
{ W.current =
W.Screen
{ W.workspace =
W.Workspace
{ W.tag = "A"
, W.layout = Layout NullLayout
, W.stack = Just $ W.Stack { W.focus = 3, W.up = [], W.down = [1, 2, 4] }
}
, W.screen = 1
, W.screenDetail = SD { screenRect = Rectangle 0 0 1920 1280 }
}
, W.visible =
[ W.Screen
{ W.workspace =
W.Workspace
{ W.tag = "B"
, W.layout = Layout NullLayout
, W.stack = Just $ W.Stack { W.focus = 5, W.up = [], W.down = [6] }
}
, W.screen = 2
, W.screenDetail = SD { screenRect = Rectangle 1920 0 1280 768 }
}
]
, W.hidden = []
, W.floating = M.empty
}
expectedWindowSet =
W.StackSet
{ W.current =
W.Screen
{ W.workspace =
W.Workspace
{ W.tag = "B"
, W.layout = Layout NullLayout
, W.stack = Just $ W.Stack { W.focus = 6, W.up = [5], W.down = [] }
}
, W.screen = 2
, W.screenDetail = SD { screenRect = Rectangle 1920 0 1280 768 }
}
, W.visible =
[ W.Screen
{ W.workspace =
W.Workspace
{ W.tag = "A"
, W.layout = Layout NullLayout
, W.stack = Just $ W.Stack { W.focus = 3, W.up = [], W.down = [1, 2, 4] }
}
, W.screen = 1
, W.screenDetail = SD { screenRect = Rectangle 0 0 1920 1280 }
}
]
, W.hidden = []
, W.floating = M.empty
}
runIdentity (goPure R (M.empty, initWindowSet, S.fromList [1..6], windowRect))
`shouldBe` (M.fromList [("B", Point 1920 600)], expectedWindowSet)
it "floating window overlapping fully in the orthogonal direction" $ do
-- ┌─────┬──────────────────┐
-- │ │ ┌───────┐ │
-- │ │ 2 │ │ │
-- │ ├──────┤-------├───┤
-- │ 1 │ 3 │ │ 3 │
-- │ ◄─┼── ◄─┼── 5 ◄─┼── │
-- │ ├──────┤-------├───┤
-- │ │ 4 │ │ │
-- │ │ └───────┘ │
-- └─────┴──────────────────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 960 0 960 400)
, (3, Rectangle 960 400 960 400)
, (4, Rectangle 960 800 960 480)
, (5, Rectangle 1360 200 200 800)
]
runNav dir st ws = runIdentity $ goPure dir (st, ws, S.fromList [1..5], windowRect)
let (st2, ws2) = runNav L (mkstate 1800 600) (mkws 3 [] [1, 2, 4, 5])
(st2, ws2) `shouldBe` (mkstate 1559 600, mkws 5 [4, 2, 1, 3] [])
let (st3, ws3) = runNav L st2 ws2
(st3, ws3) `shouldBe` (mkstate 1359 600, mkws 3 [] [1, 2, 4, 5])
let (st4, ws4) = runNav L st3 ws3
(st4, ws4) `shouldBe` (mkstate 959 600, mkws 1 [3] [2, 4, 5])
it "navigation to free-floating windows on the same screen" $ do
-- ┌──────┐
-- │ │ ┌──────┐
-- │ │ │ │
-- │ ──┼──┼─► 2 │
-- │ │ │ │
-- │ 1 │ └──────┘
-- │ │
-- │ │
-- └──────┘
let windowRect w =
Identity $ M.lookup w $ M.fromList
[ (1, Rectangle 0 0 960 1280)
, (2, Rectangle 1200 400 400 400)
]
runIdentity (goPure R (M.empty, mkws 1 [] [2], S.fromList [1, 2], windowRect))
`shouldBe` (mkstate 1200 640, mkws 2 [1] [])
it "switch between windows in Full layout" $ do
let windowRect w = Identity $ M.lookup w $ M.fromList [(1, Rectangle 0 0 1920 1280)]
runIdentity (goPure D (M.empty, mkws 1 [] [2, 3], S.fromList [1], windowRect))
`shouldBe` (M.empty, mkws 2 [1] [3])
data NullLayout a = NullLayout deriving (Show, Read, Eq)
instance LayoutClass NullLayout a
-- to make WindowSets comparable
instance Eq (Layout w) where
(==) a b = show a == show b
(/=) a b = show a /= show b
-- make a state with a position for a single workspace
mkstate :: Position -> Position -> WNState
mkstate px py = M.fromList [("A", Point px py)]
-- make a single-workspace WindowSet
mkws :: Window -> [Window] -> [Window] -> WindowSet
mkws focusedWindow upWindows downWindows = W.StackSet
{ W.current = W.Screen
{ W.workspace = W.Workspace
{ W.tag = "A"
, W.layout = Layout NullLayout
, W.stack = Just $ W.Stack { W.focus = focusedWindow, W.up = upWindows, W.down = downWindows }
}
, W.screen = 1
, W.screenDetail = SD { screenRect = Rectangle 0 0 1920 1280 }
}
, W.visible = []
, W.hidden = []
, W.floating = M.empty
}