---------------------------------------------------------------------------- -- | -- Module : XMonad.Hooks.PositionStoreHooks -- Copyright : (c) Jan Vornberger 2009 -- License : BSD3-style (see LICENSE) -- -- Maintainer : jan.vornberger@informatik.uni-oldenburg.de -- Stability : unstable -- Portability : not portable -- -- This module contains two hooks for the -- PositionStore (see "XMonad.Util.PositionStore") - a ManageHook and -- an EventHook. -- -- The ManageHook can be used to fill the PositionStore with position and size -- information about new windows. The advantage of using this hook is, that the -- information is recorded independent of the currently active layout. So the -- floating shape of the window can later be restored even if it was opened in a -- tiled layout initially. -- -- For windows, that do not request a particular position, a random position will -- be assigned. This prevents windows from piling up exactly on top of each other. -- -- The EventHook makes sure that windows are deleted from the PositionStore -- when they are closed. -- ----------------------------------------------------------------------------- module XMonad.Hooks.PositionStoreHooks ( -- * Usage -- $usage positionStoreManageHook, positionStoreEventHook ) where import XMonad import qualified XMonad.StackSet as W import XMonad.Util.PositionStore import XMonad.Hooks.ManageDocks import XMonad.Layout.Decoration import System.Random(randomRIO) import Control.Applicative((<$>)) import Control.Monad(when) import Data.Maybe import Data.Monoid import qualified Data.Set as S -- $usage -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@: -- -- > import XMonad.Hooks.PositionStoreHooks -- -- and adding 'positionStoreManageHook' to your 'ManageHook' as well -- as 'positionStoreEventHook' to your event hooks. To be accurate -- about window sizes, the module needs to know if any decoration is in effect. -- This is specified with the first argument: Supply 'Nothing' for no decoration, -- otherwise use 'Just defaultTheme' or similar to inform the module about the -- decoration theme used. -- -- > myManageHook = positionStoreManageHook Nothing <+> manageHook defaultConfig -- > myHandleEventHook = positionStoreEventHook -- > -- > main = xmonad defaultConfig { manageHook = myManageHook -- > , handleEventHook = myHandleEventHook -- > } -- positionStoreManageHook :: Maybe Theme -> ManageHook positionStoreManageHook mDecoTheme = ask >>= liftX . positionStoreInit mDecoTheme >> idHook positionStoreInit :: Maybe Theme -> Window -> X () positionStoreInit mDecoTheme w = withDisplay $ \d -> do let decoH = maybe 0 decoHeight mDecoTheme -- take decoration into account, which - in its current -- form - makes windows smaller to make room for it wa <- io $ getWindowAttributes d w ws <- gets windowset arbitraryOffsetX <- randomIntOffset arbitraryOffsetY <- randomIntOffset if (wa_x wa == 0) && (wa_y wa == 0) then do let sr@(Rectangle srX srY _ _) = screenRect . W.screenDetail . W.current $ ws modifyPosStore (\ps -> posStoreInsert ps w (Rectangle (srX + fi arbitraryOffsetX) (srY + fi arbitraryOffsetY) (fi $ wa_width wa) (decoH + fi (wa_height wa))) sr ) else do sc <- fromMaybe (W.current ws) <$> pointScreen (fi $ wa_x wa) (fi $ wa_y wa) let sr = screenRect . W.screenDetail $ sc sr' <- fmap ($ sr) (calcGap $ S.fromList [minBound .. maxBound]) -- take docks into account, accepting -- a somewhat unfortunate inter-dependency -- with 'XMonad.Hooks.ManageDocks' modifyPosStore (\ps -> posStoreInsert ps w (Rectangle (fi $ wa_x wa) (fi (wa_y wa) - fi decoH) (fi $ wa_width wa) (decoH + fi (wa_height wa))) sr' ) where randomIntOffset :: X (Int) randomIntOffset = io $ randomRIO (42, 242) positionStoreEventHook :: Event -> X All positionStoreEventHook (DestroyWindowEvent {ev_window = w, ev_event_type = et}) = do when (et == destroyNotify) $ do modifyPosStore (\ps -> posStoreRemove ps w) return (All True) positionStoreEventHook _ = return (All True)