mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-07-31 12:11:52 -07:00
Commitsd638dc8b
anda5e87e38
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 in28e9f8bc
, 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.
124 lines
5.8 KiB
Haskell
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
|