Files
xmonad-contrib/XMonad/Layout/DecorationAddons.hs
Bogdan Sinitsyn c48d81e378 Fix caching issues in ManageDocks
Commits d638dc8b and a5e87e38 introduced a per-AvoidStruts-instance
strut cache that

a) didn't get initialized at startup,
b) didn't get reinitialized after layout reset and
c) didn't get updates if it wasn't the active layout, for example when
   layoutHook = avoidStruts tall ||| avoidStruts (mirror tall)

a) + b) could be fixed by using the docksStartupHook introduced in
28e9f8bc, although this wasn't documented and having to call
docksStartupHook after setLayout is far from obvious.

By moving the strut cache from AvoidStruts instances to a global state,
b) and c) are fixed. One still has to invoke the docksStartupHook for
a), and this will be addressed in the next commit.
2016-09-07 13:26:50 +03:00

124 lines
5.8 KiB
Haskell

----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.DecorationAddons
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- Various stuff that can be added to the decoration. Most of it
-- is intended to be used by other modules. See
-- "XMonad.Layout.ButtonDecoration" for a module that makes use of this.
--
-----------------------------------------------------------------------------
module XMonad.Layout.DecorationAddons (
titleBarButtonHandler
,defaultThemeWithButtons
,handleScreenCrossing
) where
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Layout.Decoration
import XMonad.Actions.WindowMenu
import XMonad.Layout.Minimize
import XMonad.Layout.Maximize
import XMonad.Hooks.ManageDocks
import XMonad.Util.Font
import XMonad.Util.PositionStore
import Control.Applicative((<$>))
import Data.Maybe
import qualified Data.Set as S
minimizeButtonOffset :: Int
minimizeButtonOffset = 48
maximizeButtonOffset :: Int
maximizeButtonOffset = 25
closeButtonOffset :: Int
closeButtonOffset = 10
buttonSize :: Int
buttonSize = 10
-- | A function intended to be plugged into the 'decorationCatchClicksHook' of a decoration.
-- It will intercept clicks on the buttons of the decoration and invoke the associated action.
-- To actually see the buttons, you will need to use a theme that includes them.
-- See 'defaultThemeWithButtons' below.
titleBarButtonHandler :: Window -> Int -> Int -> X Bool
titleBarButtonHandler mainw distFromLeft distFromRight = do
let action = if (fi distFromLeft <= 3 * buttonSize)
then focus mainw >> windowMenu >> return True
else if (fi distFromRight >= closeButtonOffset &&
fi distFromRight <= closeButtonOffset + buttonSize)
then focus mainw >> kill >> return True
else if (fi distFromRight >= maximizeButtonOffset &&
fi distFromRight <= maximizeButtonOffset + (2 * buttonSize))
then focus mainw >> sendMessage (maximizeRestore mainw) >> return True
else if (fi distFromRight >= minimizeButtonOffset &&
fi distFromRight <= minimizeButtonOffset + buttonSize)
then focus mainw >> minimizeWindow mainw >> return True
else return False
action
-- | Intended to be used together with 'titleBarButtonHandler'. See above.
defaultThemeWithButtons :: Theme
defaultThemeWithButtons = def {
windowTitleAddons = [ (" (M)", AlignLeft)
, ("_" , AlignRightOffset minimizeButtonOffset)
, ("[]" , AlignRightOffset maximizeButtonOffset)
, ("X" , AlignRightOffset closeButtonOffset)
]
}
-- | A function intended to be plugged into the 'decorationAfterDraggingHook' of a decoration.
-- It will check if the window has been dragged onto another screen and shift it there.
-- The PositionStore is also updated accordingly, as this is designed to be used together
-- with "XMonad.Layout.PositionStoreFloat".
handleScreenCrossing :: Window -> Window -> X Bool
handleScreenCrossing w decoWin = withDisplay $ \d -> do
root <- asks theRoot
(_, _, _, px, py, _, _, _) <- io $ queryPointer d root
ws <- gets windowset
sc <- fromMaybe (W.current ws) <$> pointScreen (fi px) (fi py)
maybeWksp <- screenWorkspace $ W.screen sc
let targetWksp = maybeWksp >>= \wksp ->
W.findTag w ws >>= \currentWksp ->
if (currentWksp /= wksp)
then Just wksp
else Nothing
case targetWksp of
Just wksp -> do
-- find out window under cursor on target workspace
-- apparently we have to switch to the workspace first
-- to make this work, which unforunately introduces some flicker
windows $ \ws' -> W.view wksp ws'
(_, _, selWin, _, _, _, _, _) <- io $ queryPointer d root
-- adjust PositionStore
let oldScreenRect = screenRect . W.screenDetail $ W.current ws
newScreenRect = screenRect . W.screenDetail $ sc
{-- somewhat ugly hack to get proper ScreenRect,
creates unwanted inter-dependencies
TODO: get ScreenRects in a proper way --}
oldScreenRect' <- fmap ($ oldScreenRect) (calcGap $ S.fromList [minBound .. maxBound])
newScreenRect' <- fmap ($ newScreenRect) (calcGap $ S.fromList [minBound .. maxBound])
wa <- io $ getWindowAttributes d decoWin
modifyPosStore (\ps ->
posStoreMove ps w (fi $ wa_x wa) (fi $ wa_y wa)
oldScreenRect' newScreenRect')
-- set focus correctly so the window will be inserted
-- at the correct position on the target workspace
-- and then shift the window
windows $ \ws' -> W.shiftWin wksp w . W.focusWindow selWin $ ws'
-- return True to signal that screen crossing has taken place
return True
Nothing -> return False