aboutsummaryrefslogblamecommitdiffstats
path: root/XMonad/Actions/Plane.hs
blob: a3bb6c37cef83d8cb2333498e4fa14a308104d87 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11










                                                                              
                                                                           

































































                                                                                   

                                                                           








                                                                              
                                 



















                                                                            
                                                

                
 
       




                                                            





                                                                          

                                       

                                      



                                                                             
                                       
                                          
                                                                       

                                


                                                      
 







                                                                          
-----------------------------------------------------------------------------
-- |
-- Module      :  XMonad.Actions.Plane
-- Copyright   :  (c) Malebria <malebria@riseup.net>,
-- License     :  BSD3-style (see LICENSE)
--
-- Maintainer  :  Malebria <malebria@riseup.net>
-- Stability   :  unstable
-- Portability :  unportable
--
-- This module has functions to navigate through workspaces in a bidimensional
-- manner.  It allows the organization of workspaces in lines, and provides
-- functions to move and shift windows in all four directions (left, up, right
-- and down) possible in a surface.
--
-- This functionality was inspired by GNOME (finite) and KDE (infinite)
-- keybindings for workspace navigation, and by "XMonad.Actions.CycleWS" for
-- the idea of applying this approach to XMonad.
-----------------------------------------------------------------------------

module XMonad.Actions.Plane
    (
    -- * Usage
    -- $usage

    -- * Data types
    Direction (..)
    , Limits (..)

    -- * Navigating through workspaces
    -- $navigating
    , planeShift
    , planeMove
    )
    where

import Control.Monad
import Data.List hiding (union)
import Data.Maybe

import XMonad
import XMonad.StackSet hiding (workspaces)

-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
--
-- > import XMonad.Actions.Plane
-- >
-- > main = xmonad defaultConfig {keys = myKeys}
-- >
-- > myKeys conf = union (keys defaultConfig conf) $ myNewKeys conf
-- >
-- > myNewkeys (XConfig {modMask = m}) =
-- >     fromList
-- >     [ ((keyMask .|. m, keySym), function 3 Finite direction)
-- >     | (keySym, direction) <- zip [xK_Left .. xK_Down] $ enumFrom ToLeft
-- >     , (keyMask, function) <- [(0, planeMove), (shiftMask, planeShift)]
-- >     ]
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".

-- | Direction to go in the plane.
data Direction =  ToLeft | ToUp | ToRight | ToDown deriving Enum

-- | Defines whether it's a finite or a circular organization of workspaces.
data Limits
    = Finite   -- ^ When you're at a edge of the plane, there's no way to move
               -- to the next region.
    | Circular -- ^ If you try to move, you'll get to the other edge, on the
               -- other side.
    deriving Eq

-- $navigating
--
-- There're two parameters that must be provided to navigate, and it's a good
-- idea to use them with the same values in each keybinding.
--
-- The first is the number of lines in which the workspaces are going to be
-- organized.  It's possible to use a number of lines that is not a divisor
-- of the number of workspaces, but the results are better when using a
-- divisor.  If it's not a divisor, the last line will have the remaining
-- workspaces.
--
-- The other one is 'Limits'.

-- | Shift a window to the next workspace in 'Direction'.  Note that this will
-- also move to the next workspace.
planeShift
    :: Int  -- ^ Number of lines.
    -> Limits
    -> Direction
    -> X ()
planeShift = plane shift'

shift' ::
    (Eq s, Eq i, Ord a) => i -> StackSet i l a s sd -> StackSet i l a s sd
shift' area = greedyView area . shift area

-- | Move to the next workspace in 'Direction'.
planeMove
    :: Int  -- ^ Number of columns.
    -> Limits
    -> Direction
    -> X ()
planeMove = plane greedyView

plane ::
    (WorkspaceId -> WindowSet -> WindowSet) -> Int -> Limits -> Direction ->
    X ()
plane function numberLines limits direction = do
    state <- get
    xconf <- ask

    let
        horizontal f =
            if line < areasLine
                then mod (f column) columns + lineNumber
                else mod (f column) areasColumn + lineNumber

        vertical f =
            if column >= areasColumn
                then mod (f currentWS columns) $ areasLine * columns
                else mod (f currentWS columns) $ (areasLine + 1) * columns

        lineNumber = line * columns
        areasLine = div areas columns
        areasColumn = mod areas columns
        line = div currentWS columns
        column = mod currentWS columns

        columns =
            if mod areas numberLines == 0 then preColumns else preColumns + 1

        currentWS = fromJust mCurrentWS
        preColumns = div areas numberLines
        mCurrentWS = elemIndex (currentTag $ windowset state) areaNames
        areas = length areaNames

        run condition position =
            when (limits == Circular || condition) $
            windows $ function $ areaNames !! position

        areaNames = workspaces $ config $ xconf

    when (isJust mCurrentWS) $
        case direction of
            ToUp    -> run (line   /= 0                ) $ vertical (-)
            ToDown  -> run (currentWS + columns < areas) $ vertical (+)
            ToLeft  -> run (column /= 0                ) $ horizontal pred
            ToRight -> run (column /= columns - 1      ) $ horizontal succ