mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-05-19 11:30:22 -07:00
The user may modify the list of workspace tags that results form applying the dynamic order. This way one may filter workspaces they don't want in the order (e.g. "NSP") or apply any transformation he wishes to the list of tags.
203 lines
7.2 KiB
Haskell
203 lines
7.2 KiB
Haskell
{-# LANGUAGE DeriveDataTypeable #-}
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- |
|
|
-- Module : XMonad.Actions.DynamicWorkspaceOrder
|
|
-- Copyright : (c) Brent Yorgey 2009
|
|
-- License : BSD-style (see LICENSE)
|
|
--
|
|
-- Maintainer : <byorgey@gmail.com>
|
|
-- Stability : experimental
|
|
-- Portability : unportable
|
|
--
|
|
-- Remember a dynamically updateable ordering on workspaces, together
|
|
-- with tools for using this ordering with "XMonad.Actions.CycleWS"
|
|
-- and "XMonad.Hooks.DynamicLog".
|
|
--
|
|
-----------------------------------------------------------------------------
|
|
|
|
module XMonad.Actions.DynamicWorkspaceOrder
|
|
( -- * Usage
|
|
-- $usage
|
|
|
|
getWsCompareByOrder
|
|
, getSortByOrder
|
|
, swapWith
|
|
, updateName
|
|
, removeName
|
|
|
|
, moveTo
|
|
, moveToGreedy
|
|
, shiftTo
|
|
|
|
, withNthWorkspace'
|
|
, withNthWorkspace
|
|
|
|
) where
|
|
|
|
import XMonad
|
|
import qualified XMonad.StackSet as W
|
|
import qualified XMonad.Util.ExtensibleState as XS
|
|
|
|
import XMonad.Util.WorkspaceCompare (WorkspaceCompare, WorkspaceSort, mkWsSort)
|
|
import XMonad.Actions.CycleWS (findWorkspace, WSType(..), Direction1D(..), doTo)
|
|
|
|
import qualified Data.Map as M
|
|
import qualified Data.Set as S
|
|
import Data.Maybe (fromJust, fromMaybe)
|
|
import Data.Ord (comparing)
|
|
|
|
-- $usage
|
|
-- You can use this module by importing it into your ~\/.xmonad\/xmonad.hs file:
|
|
--
|
|
-- > import qualified XMonad.Actions.DynamicWorkspaceOrder as DO
|
|
--
|
|
-- Then add keybindings to swap the order of workspaces (these
|
|
-- examples use "XMonad.Util.EZConfig" emacs-style keybindings):
|
|
--
|
|
-- > , ("M-C-<R>", DO.swapWith Next NonEmptyWS)
|
|
-- > , ("M-C-<L>", DO.swapWith Prev NonEmptyWS)
|
|
--
|
|
-- See "XMonad.Actions.CycleWS" for information on the possible
|
|
-- arguments to 'swapWith'.
|
|
--
|
|
-- However, by itself this will do nothing; 'swapWith' does not change
|
|
-- the actual workspaces in any way. It simply keeps track of an
|
|
-- auxiliary ordering on workspaces. Anything which cares about the
|
|
-- order of workspaces must be updated to use the auxiliary ordering.
|
|
--
|
|
-- To change the order in which workspaces are displayed by
|
|
-- "XMonad.Hooks.DynamicLog", use 'getSortByOrder' in your
|
|
-- 'XMonad.Hooks.DynamicLog.ppSort' field, for example:
|
|
--
|
|
-- > ... dynamicLogWithPP $ byorgeyPP {
|
|
-- > ...
|
|
-- > , ppSort = DO.getSortByOrder
|
|
-- > ...
|
|
-- > }
|
|
--
|
|
-- To use workspace cycling commands like those from
|
|
-- "XMonad.Actions.CycleWS", use the versions of 'moveTo',
|
|
-- 'moveToGreedy', and 'shiftTo' exported by this module. For example:
|
|
--
|
|
-- > , ("M-S-<R>", DO.shiftTo Next HiddenNonEmptyWS)
|
|
-- > , ("M-S-<L>", DO.shiftTo Prev HiddenNonEmptyWS)
|
|
-- > , ("M-<R>", DO.moveTo Next HiddenNonEmptyWS)
|
|
-- > , ("M-<L>", DO.moveTo Prev HiddenNonEmptyWS)
|
|
--
|
|
-- For slight variations on these, use the source for examples and
|
|
-- tweak as desired.
|
|
|
|
-- | Extensible state storage for the workspace order.
|
|
data WSOrderStorage = WSO { unWSO :: Maybe (M.Map WorkspaceId Int) }
|
|
deriving (Typeable, Read, Show)
|
|
|
|
instance ExtensionClass WSOrderStorage where
|
|
initialValue = WSO Nothing
|
|
extensionType = PersistentExtension
|
|
|
|
-- | Lift a Map function to a function on WSOrderStorage.
|
|
withWSO :: (M.Map WorkspaceId Int -> M.Map WorkspaceId Int)
|
|
-> (WSOrderStorage -> WSOrderStorage)
|
|
withWSO f = WSO . fmap f . unWSO
|
|
|
|
-- | Update the ordering storage: initialize if it doesn't yet exist;
|
|
-- add newly created workspaces at the end as necessary.
|
|
updateOrder :: X ()
|
|
updateOrder = do
|
|
WSO mm <- XS.get
|
|
case mm of
|
|
Nothing -> do
|
|
-- initialize using ordering of workspaces from the user's config
|
|
ws <- asks (workspaces . config)
|
|
XS.put . WSO . Just . M.fromList $ zip ws [0..]
|
|
Just m -> do
|
|
-- check for new workspaces and add them at the end
|
|
curWs <- gets (S.fromList . map W.tag . W.workspaces . windowset)
|
|
let mappedWs = M.keysSet m
|
|
newWs = curWs `S.difference` mappedWs
|
|
nextIndex = 1 + maximum (-1 : M.elems m)
|
|
newWsIxs = zip (S.toAscList newWs) [nextIndex..]
|
|
XS.modify . withWSO . M.union . M.fromList $ newWsIxs
|
|
|
|
-- | A comparison function which orders workspaces according to the
|
|
-- stored dynamic ordering.
|
|
getWsCompareByOrder :: X WorkspaceCompare
|
|
getWsCompareByOrder = do
|
|
updateOrder
|
|
-- after the call to updateOrder we are guaranteed that the dynamic
|
|
-- workspace order is initialized and contains all existing
|
|
-- workspaces.
|
|
WSO (Just m) <- XS.get
|
|
return $ comparing (fromMaybe 1000 . flip M.lookup m)
|
|
|
|
-- | Sort workspaces according to the stored dynamic ordering.
|
|
getSortByOrder :: X WorkspaceSort
|
|
getSortByOrder = mkWsSort getWsCompareByOrder
|
|
|
|
-- | Swap the current workspace with another workspace in the stored
|
|
-- dynamic order.
|
|
swapWith :: Direction1D -> WSType -> X ()
|
|
swapWith dir which = findWorkspace getSortByOrder dir which 1 >>= swapWithCurrent
|
|
|
|
-- | Swap the given workspace with the current one.
|
|
swapWithCurrent :: WorkspaceId -> X ()
|
|
swapWithCurrent w = do
|
|
cur <- gets (W.currentTag . windowset)
|
|
swapOrder w cur
|
|
|
|
-- | Swap the two given workspaces in the dynamic order.
|
|
swapOrder :: WorkspaceId -> WorkspaceId -> X ()
|
|
swapOrder w1 w2 = do
|
|
io $ print (w1,w2)
|
|
WSO (Just m) <- XS.get
|
|
let [i1,i2] = map (fromJust . flip M.lookup m) [w1,w2]
|
|
XS.modify (withWSO (M.insert w1 i2 . M.insert w2 i1))
|
|
windows id -- force a status bar update
|
|
|
|
-- | Update the name of a workspace in the stored order.
|
|
updateName :: WorkspaceId -> WorkspaceId -> X ()
|
|
updateName oldId newId = XS.modify . withWSO $ changeKey oldId newId
|
|
|
|
-- | Remove a workspace from the stored order.
|
|
removeName :: WorkspaceId -> X ()
|
|
removeName = XS.modify . withWSO . M.delete
|
|
|
|
-- | Update a key in a Map.
|
|
changeKey :: Ord k => k -> k -> M.Map k a -> M.Map k a
|
|
changeKey oldKey newKey oldMap =
|
|
case M.updateLookupWithKey (\_ _ -> Nothing) oldKey oldMap of
|
|
(Nothing, _) -> oldMap
|
|
(Just val, newMap) -> M.insert newKey val newMap
|
|
|
|
-- | View the next workspace of the given type in the given direction,
|
|
-- where \"next\" is determined using the dynamic workspace order.
|
|
moveTo :: Direction1D -> WSType -> X ()
|
|
moveTo dir t = doTo dir t getSortByOrder (windows . W.view)
|
|
|
|
-- | Same as 'moveTo', but using 'greedyView' instead of 'view'.
|
|
moveToGreedy :: Direction1D -> WSType -> X ()
|
|
moveToGreedy dir t = doTo dir t getSortByOrder (windows . W.greedyView)
|
|
|
|
-- | Shift the currently focused window to the next workspace of the
|
|
-- given type in the given direction, using the dynamic workspace order.
|
|
shiftTo :: Direction1D -> WSType -> X ()
|
|
shiftTo dir t = doTo dir t getSortByOrder (windows . W.shift)
|
|
|
|
-- | Do something with the nth workspace in the dynamic order after
|
|
-- transforming it. The callback is given the workspace's tag as well
|
|
-- as the 'WindowSet' of the workspace itself.
|
|
withNthWorkspace' :: ([WorkspaceId] -> [WorkspaceId]) -> (String -> WindowSet -> WindowSet) -> Int -> X ()
|
|
withNthWorkspace' tr job wnum = do
|
|
sort <- getSortByOrder
|
|
ws <- gets (tr . map W.tag . sort . W.workspaces . windowset)
|
|
case drop wnum ws of
|
|
(w:_) -> windows $ job w
|
|
[] -> return ()
|
|
|
|
-- | Do something with the nth workspace in the dynamic order. The
|
|
-- callback is given the workspace's tag as well as the 'WindowSet'
|
|
-- of the workspace itself.
|
|
withNthWorkspace :: (String -> WindowSet -> WindowSet) -> Int -> X ()
|
|
withNthWorkspace = withNthWorkspace' id
|