{-# LANGUAGE DeriveDataTypeable #-}
----------------------------------------------------------------------------
-- |
-- Module      :  XMonad.Hooks.CurrentWorkspaceOnTop
-- Copyright   :  (c) Jan Vornberger 2009
-- License     :  BSD3-style (see LICENSE)
--
-- Maintainer  :  jan.vornberger@informatik.uni-oldenburg.de
-- Stability   :  unstable
-- Portability :  not portable
--
-- Ensures that the windows of the current workspace are always in front
-- of windows that are located on other visible screens. This becomes important
-- if you use decoration and drag windows from one screen to another. Using this
-- module, the dragged window will always be in front of other windows.
--
-----------------------------------------------------------------------------

module XMonad.Hooks.CurrentWorkspaceOnTop (
    -- * Usage
    -- $usage
    currentWorkspaceOnTop
    ) where

import XMonad
import qualified XMonad.StackSet as S
import qualified XMonad.Util.ExtensibleState as XS
import Control.Monad(when)
import qualified Data.Map as M

-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.CurrentWorkspaceOnTop
-- >
-- > main = xmonad $ def {
-- >    ...
-- >    logHook = currentWorkspaceOnTop
-- >    ...
-- >  }
--

data CWOTState = CWOTS String deriving Typeable

instance ExtensionClass CWOTState where
  initialValue = CWOTS ""

currentWorkspaceOnTop :: X ()
currentWorkspaceOnTop = withDisplay $ \d -> do
    ws <- gets windowset
    (CWOTS lastTag) <- XS.get
    let curTag = S.tag . S.workspace . S.current $ ws
    when (curTag /= lastTag) $ do
        -- the following is more or less a reimplementation of what's happening in "XMonad.Operation"
        let s = S.current ws
            wsp = S.workspace s
            viewrect = screenRect $ S.screenDetail s
            tmpStack = (S.stack wsp) >>= S.filter (`M.notMember` S.floating ws)
        (rs, ml') <- runLayout wsp { S.stack = tmpStack } viewrect
        updateLayout curTag ml'
        let this = S.view curTag ws
            fltWins = filter (flip M.member (S.floating ws)) $ S.index this
            wins = fltWins ++ (map fst rs)  -- order: first all floating windows, then the order the layout returned
        -- end of reimplementation

        when (not . null $ wins) $ do
            io $ raiseWindow d (head wins)  -- raise first window of current workspace to the very top,
            io $ restackWindows d wins      -- then use restackWindows to let all other windows from the workspace follow
        XS.put(CWOTS curTag)