mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-05-19 11:30:22 -07:00
Whenever possible, prefer the safe wrappers withWindowAttributes or safeGetWindowAttributes to getWindowAttributes. Places where these are not applicable are limited to layouts, where there is not good "default value" to give back in case these calls fail. In these cases, we let the exception handling of the layout mechanism handle it and fall back to the Full layout. Fixes: https://github.com/xmonad/xmonad-contrib/issues/146
93 lines
3.4 KiB
Haskell
93 lines
3.4 KiB
Haskell
-----------------------------------------------------------------------------
|
|
-- |
|
|
-- Module : XMonad.Actions.TiledWindowDragging
|
|
-- Description : Change the position of windows by dragging them.
|
|
-- Copyright : (c) 2020 Leon Kowarschick
|
|
-- License : BSD3-style (see LICENSE)
|
|
--
|
|
-- Maintainer : Leon Kowarschick. <thereal.elkowar@gmail.com>
|
|
-- Stability : unstable
|
|
-- Portability : unportable
|
|
--
|
|
-- Provides an action that allows you to change the position of windows by dragging them around.
|
|
--
|
|
-----------------------------------------------------------------------------
|
|
|
|
module XMonad.Actions.TiledWindowDragging
|
|
(
|
|
-- * Usage
|
|
-- $usage
|
|
dragWindow
|
|
)
|
|
where
|
|
|
|
import XMonad
|
|
import XMonad.Prelude
|
|
import qualified XMonad.StackSet as W
|
|
import XMonad.Layout.DraggingVisualizer
|
|
|
|
-- $usage
|
|
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
|
--
|
|
-- > import XMonad.Actions.TiledWindowDragging
|
|
-- > import XMonad.Layout.DraggingVisualizer
|
|
--
|
|
-- then edit your 'layoutHook' by adding the draggingVisualizer to your layout:
|
|
--
|
|
-- > myLayout = draggingVisualizer $ layoutHook def
|
|
--
|
|
-- Then add a mouse binding for 'dragWindow':
|
|
--
|
|
-- > , ((modMask .|. shiftMask, button1), dragWindow)
|
|
--
|
|
-- For detailed instructions on editing your mouse bindings, see
|
|
-- "XMonad.Doc.Extending#Editing_mouse_bindings".
|
|
|
|
|
|
|
|
-- | Create a mouse binding for this to be able to drag your windows around.
|
|
-- You need "XMonad.Layout.DraggingVisualizer" for this to look good.
|
|
dragWindow :: Window -> X ()
|
|
dragWindow window = whenX (isClient window) $ withDisplay $ \dpy ->
|
|
withWindowAttributes dpy window $ \wa -> do
|
|
focus window
|
|
(offsetX, offsetY) <- getPointerOffset window
|
|
let (winX, winY, winWidth, winHeight) = getWindowPlacement wa
|
|
|
|
mouseDrag
|
|
(\posX posY ->
|
|
let rect = Rectangle (fi (fi winX + (posX - fi offsetX)))
|
|
(fi (fi winY + (posY - fi offsetY)))
|
|
(fi winWidth)
|
|
(fi winHeight)
|
|
in sendMessage $ DraggingWindow window rect
|
|
)
|
|
(sendMessage DraggingStopped >> performWindowSwitching window)
|
|
|
|
|
|
-- | get the pointer offset relative to the given windows root coordinates
|
|
getPointerOffset :: Window -> X (Int, Int)
|
|
getPointerOffset win = do
|
|
(_, _, _, oX, oY, _, _, _) <- withDisplay (\d -> io $ queryPointer d win)
|
|
return (fi oX, fi oY)
|
|
|
|
-- | return a tuple of windowX, windowY, windowWidth, windowHeight
|
|
getWindowPlacement :: WindowAttributes -> (Int, Int, Int, Int)
|
|
getWindowPlacement wa = (fi $ wa_x wa, fi $ wa_y wa, fi $ wa_width wa, fi $ wa_height wa)
|
|
|
|
performWindowSwitching :: Window -> X ()
|
|
performWindowSwitching win = do
|
|
root <- asks theRoot
|
|
(_, _, selWin, _, _, _, _, _) <- withDisplay (\d -> io $ queryPointer d root)
|
|
ws <- gets windowset
|
|
let allWindows = W.index ws
|
|
when ((win `elem` allWindows) && (selWin `elem` allWindows)) $ do
|
|
let allWindowsSwitched = map (switchEntries win selWin) allWindows
|
|
(ls, t : rs) <- pure $ break (== win) allWindowsSwitched
|
|
let newStack = W.Stack t (reverse ls) rs
|
|
windows $ W.modify' $ const newStack
|
|
where
|
|
switchEntries a b x | x == a = b
|
|
| x == b = a
|
|
| otherwise = x
|