{-# LANGUAGE ViewPatterns #-}

-----------------------------------------------------------------------------
-- |
-- Module       : XMonad.Actions.RotSlaves
-- Description  : Rotate all windows except the master window and keep the focus in place.
-- Copyright    : (c) Hans Philipp Annen <haphi@gmx.net>, Mischa Dieterle <der_m@freenet.de>
-- License      : BSD3-style (see LICENSE)
--
-- Maintainer   : Hans Philipp Annen <haphi@gmx.net>
-- Stability    : stable
-- Portability  : unportable
--
-- Rotate all windows except the master window and keep the focus in
-- place.
-----------------------------------------------------------------------------
module XMonad.Actions.RotSlaves (
        -- $usage
        rotSlaves', rotSlavesUp, rotSlavesDown,
        rotAll', rotAllUp, rotAllDown
        ) where

import XMonad
import XMonad.StackSet
import XMonad.Prelude

-- $usage
--
-- To use this module, import it with:
--
-- > import XMonad.Actions.RotSlaves
--
-- and add whatever keybindings you would like, for example:
--
-- > , ((modm .|. shiftMask, xK_Tab   ), rotSlavesUp)
--
-- This operation will rotate all windows except the master window,
-- while the focus stays where it is. It is useful together with the
-- TwoPane layout (see "XMonad.Layout.TwoPane").
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".

-- | Rotate the windows in the current stack, excluding the first one
--   (master).
rotSlavesUp,rotSlavesDown :: X ()
rotSlavesUp :: X ()
rotSlavesUp   = (WindowSet -> WindowSet) -> X ()
windows ((WindowSet -> WindowSet) -> X ())
-> (WindowSet -> WindowSet) -> X ()
forall a b. (a -> b) -> a -> b
$ (Stack Window -> Stack Window) -> WindowSet -> WindowSet
forall a i l s sd.
(Stack a -> Stack a) -> StackSet i l a s sd -> StackSet i l a s sd
modify' (([Window] -> [Window]) -> Stack Window -> Stack Window
forall a. ([a] -> [a]) -> Stack a -> Stack a
rotSlaves' (\[Window]
l -> [Window] -> [Window]
forall a. [a] -> [a]
tail [Window]
l[Window] -> [Window] -> [Window]
forall a. [a] -> [a] -> [a]
++[[Window] -> Window
forall a. [a] -> a
head [Window]
l]))
rotSlavesDown :: X ()
rotSlavesDown = (WindowSet -> WindowSet) -> X ()
windows ((WindowSet -> WindowSet) -> X ())
-> (WindowSet -> WindowSet) -> X ()
forall a b. (a -> b) -> a -> b
$ (Stack Window -> Stack Window) -> WindowSet -> WindowSet
forall a i l s sd.
(Stack a -> Stack a) -> StackSet i l a s sd -> StackSet i l a s sd
modify' (([Window] -> [Window]) -> Stack Window -> Stack Window
forall a. ([a] -> [a]) -> Stack a -> Stack a
rotSlaves' (\[Window]
l -> [Window] -> Window
forall a. [a] -> a
last [Window]
l Window -> [Window] -> [Window]
forall a. a -> [a] -> [a]
: [Window] -> [Window]
forall a. [a] -> [a]
init [Window]
l))

-- | The actual rotation, as a pure function on the window stack.
rotSlaves' :: ([a] -> [a]) -> Stack a -> Stack a
rotSlaves' :: forall a. ([a] -> [a]) -> Stack a -> Stack a
rotSlaves' [a] -> [a]
_ s :: Stack a
s@(Stack a
_ [] []) = Stack a
s
rotSlaves' [a] -> [a]
f   (Stack a
t [] [a]
rs) = a -> [a] -> [a] -> Stack a
forall a. a -> [a] -> [a] -> Stack a
Stack a
t [] ([a] -> [a]
f [a]
rs)                -- Master has focus
rotSlaves' [a] -> [a]
f s :: Stack a
s@(Stack a
_ [a]
ls [a]
_ ) = a -> [a] -> [a] -> Stack a
forall a. a -> [a] -> [a] -> Stack a
Stack a
t' ([a] -> [a]
forall a. [a] -> [a]
reverse [a]
revls') [a]
rs'    -- otherwise
    where  ([a] -> NonEmpty a
forall a. HasCallStack => [a] -> NonEmpty a
notEmpty -> a
master :| [a]
ws)      = Stack a -> [a]
forall a. Stack a -> [a]
integrate Stack a
s
           ([a]
revls', [a] -> NonEmpty a
forall a. HasCallStack => [a] -> NonEmpty a
notEmpty -> a
t' :| [a]
rs') = Int -> [a] -> ([a], [a])
forall a. Int -> [a] -> ([a], [a])
splitAt ([a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
ls) (a
mastera -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a] -> [a]
f [a]
ws)

-- | Rotate all the windows in the current stack.
rotAllUp,rotAllDown :: X ()
rotAllUp :: X ()
rotAllUp   = (WindowSet -> WindowSet) -> X ()
windows ((WindowSet -> WindowSet) -> X ())
-> (WindowSet -> WindowSet) -> X ()
forall a b. (a -> b) -> a -> b
$ (Stack Window -> Stack Window) -> WindowSet -> WindowSet
forall a i l s sd.
(Stack a -> Stack a) -> StackSet i l a s sd -> StackSet i l a s sd
modify' (([Window] -> [Window]) -> Stack Window -> Stack Window
forall a. ([a] -> [a]) -> Stack a -> Stack a
rotAll' (\[Window]
l -> [Window] -> [Window]
forall a. [a] -> [a]
tail [Window]
l[Window] -> [Window] -> [Window]
forall a. [a] -> [a] -> [a]
++[[Window] -> Window
forall a. [a] -> a
head [Window]
l]))
rotAllDown :: X ()
rotAllDown = (WindowSet -> WindowSet) -> X ()
windows ((WindowSet -> WindowSet) -> X ())
-> (WindowSet -> WindowSet) -> X ()
forall a b. (a -> b) -> a -> b
$ (Stack Window -> Stack Window) -> WindowSet -> WindowSet
forall a i l s sd.
(Stack a -> Stack a) -> StackSet i l a s sd -> StackSet i l a s sd
modify' (([Window] -> [Window]) -> Stack Window -> Stack Window
forall a. ([a] -> [a]) -> Stack a -> Stack a
rotAll' (\[Window]
l -> [Window] -> Window
forall a. [a] -> a
last [Window]
l Window -> [Window] -> [Window]
forall a. a -> [a] -> [a]
: [Window] -> [Window]
forall a. [a] -> [a]
init [Window]
l))

-- | The actual rotation, as a pure function on the window stack.
rotAll' :: ([a] -> [a]) -> Stack a -> Stack a
rotAll' :: forall a. ([a] -> [a]) -> Stack a -> Stack a
rotAll' [a] -> [a]
f Stack a
s = a -> [a] -> [a] -> Stack a
forall a. a -> [a] -> [a] -> Stack a
Stack a
r ([a] -> [a]
forall a. [a] -> [a]
reverse [a]
revls) [a]
rs
    where ([a]
revls, [a] -> NonEmpty a
forall a. HasCallStack => [a] -> NonEmpty a
notEmpty -> a
r :| [a]
rs) = Int -> [a] -> ([a], [a])
forall a. Int -> [a] -> ([a], [a])
splitAt ([a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Stack a -> [a]
forall a. Stack a -> [a]
up Stack a
s)) ([a] -> [a]
f (Stack a -> [a]
forall a. Stack a -> [a]
integrate Stack a
s))