mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-05-19 03:20:21 -07:00
144 lines
5.4 KiB
Haskell
144 lines
5.4 KiB
Haskell
----------------------------------------------------------------------------
|
|
-- |
|
|
-- Module : XMonad.Actions.Minimize
|
|
-- Copyright : (c) Bogdan Sinitsyn (2016)
|
|
-- License : BSD3-style (see LICENSE)
|
|
--
|
|
-- Maintainer : Bogdan Sinitsyn <bogdan.sinitsyn@gmail.com>
|
|
-- Stability : unstable
|
|
-- Portability : not portable
|
|
--
|
|
-- Adds actions for minimizing and maximizing windows
|
|
--
|
|
-- This module should be used with "XMonad.Layout.Minimize". Add 'minimize' to your
|
|
-- layout modifiers as described in "XMonad.Layout.Minimized" and use actions from
|
|
-- this module
|
|
--
|
|
-- Possible keybindings:
|
|
--
|
|
-- > , ((modm, xK_m ), withFocused minimizeWindow)
|
|
-- > , ((modm .|. shiftMask, xK_m ), withLastMinimized maximizeWindowAndFocus)
|
|
--
|
|
-----------------------------------------------------------------------------
|
|
|
|
module XMonad.Actions.Minimize
|
|
( -- * Usage
|
|
-- $usage
|
|
minimizeWindow
|
|
, maximizeWindow
|
|
, maximizeWindowAndFocus
|
|
, withLastMinimized
|
|
, withLastMinimized'
|
|
, withFirstMinimized
|
|
, withFirstMinimized'
|
|
, withMinimized
|
|
) where
|
|
|
|
import XMonad
|
|
import qualified XMonad.StackSet as W
|
|
|
|
import qualified XMonad.Layout.BoringWindows as BW
|
|
import qualified XMonad.Util.ExtensibleState as XS
|
|
import XMonad.Util.Minimize
|
|
import XMonad.Util.WindowProperties (getProp32)
|
|
|
|
import Foreign.C.Types (CLong)
|
|
import Control.Monad (join)
|
|
import Data.Maybe (fromMaybe, listToMaybe)
|
|
import qualified Data.List as L
|
|
import qualified Data.Map as M
|
|
|
|
-- $usage
|
|
-- Import this module with "XMonad.Layout.Minimize" and "XMonad.Layout.BoringWindows":
|
|
-- > import XMonad.Actions.Minimize
|
|
-- > import XMonad.Layout.Minimize
|
|
-- > import qualified XMonad.Layout.BoringWindows as BW
|
|
--
|
|
-- Then apply 'minimize' and 'boringWindows' to your layout hook and use some
|
|
-- actions from this module:
|
|
-- > main = xmonad def { layoutHook = minimize . BW.boringWindows $ whatever }
|
|
-- Example keybindings:
|
|
-- > , ((modm, xK_m ), withFocused minimizeWindow )
|
|
-- > , ((modm .|. shiftMask, xK_m ), withLastMinimized maximizeWindow)
|
|
|
|
setMinimizedState :: Window -> Int -> (CLong -> [CLong] -> [CLong]) -> X ()
|
|
setMinimizedState win st f = do
|
|
setWMState win st
|
|
withDisplay $ \dpy -> do
|
|
wm_state <- getAtom "_NET_WM_STATE"
|
|
hidden <- fromIntegral <$> getAtom "_NET_WM_STATE_HIDDEN"
|
|
wstate <- fromMaybe [] <$> getProp32 wm_state win
|
|
io $ changeProperty32 dpy win wm_state aTOM propModeReplace (f hidden wstate)
|
|
|
|
setMinimized :: Window -> X ()
|
|
setMinimized win = setMinimizedState win iconicState (:)
|
|
|
|
setNotMinimized :: Window -> X ()
|
|
setNotMinimized win = setMinimizedState win normalState L.delete
|
|
|
|
-- It does not just set minimizedStack to newWindows because it should save
|
|
-- order in which elements were added (newer first)
|
|
modified :: (RectMap -> RectMap) -> X Bool
|
|
modified f = XS.modified $
|
|
\Minimized { rectMap = oldRectMap, minimizedStack = oldStack } ->
|
|
let newRectMap = f oldRectMap
|
|
newWindows = M.keys newRectMap
|
|
in Minimized { rectMap = newRectMap
|
|
, minimizedStack = (newWindows L.\\ oldStack)
|
|
++
|
|
(oldStack `L.intersect` newWindows)
|
|
}
|
|
|
|
|
|
-- | Minimize a window
|
|
minimizeWindow :: Window -> X ()
|
|
minimizeWindow w = withWindowSet $ \ws ->
|
|
whenX (modified $ M.insert w (M.lookup w $ W.floating ws)) $ do
|
|
setMinimized w
|
|
windows $ W.sink w
|
|
BW.focusDown
|
|
|
|
|
|
-- | Maximize window and apply a function to maximized window and 'WindowSet'
|
|
maximizeWindowAndChangeWSet :: (Window -> WindowSet -> WindowSet) -> Window -> X ()
|
|
maximizeWindowAndChangeWSet f w = do
|
|
mrect <- XS.gets (join . M.lookup w . rectMap)
|
|
whenX (modified $ M.delete w) $ do
|
|
setNotMinimized w
|
|
broadcastMessage BW.UpdateBoring
|
|
windows $ f w . maybe id (W.float w) mrect
|
|
|
|
-- | Just maximize a window without focusing
|
|
maximizeWindow :: Window -> X ()
|
|
maximizeWindow = maximizeWindowAndChangeWSet $ const id
|
|
|
|
-- | Maximize a window and then focus it
|
|
maximizeWindowAndFocus :: Window -> X ()
|
|
maximizeWindowAndFocus = maximizeWindowAndChangeWSet W.focusWindow
|
|
|
|
-- | Perform an action with first minimized window on current workspace
|
|
-- or do nothing if there is no minimized windows on current workspace
|
|
withFirstMinimized :: (Window -> X ()) -> X ()
|
|
withFirstMinimized action = withFirstMinimized' (flip whenJust action)
|
|
|
|
-- | Like withFirstMinimized but the provided action is always invoked with a
|
|
-- 'Maybe Window', that will be nothing if there is no first minimized window.
|
|
withFirstMinimized' :: (Maybe Window -> X ()) -> X ()
|
|
withFirstMinimized' action = withMinimized (action . listToMaybe . reverse)
|
|
|
|
-- | Perform an action with last minimized window on current workspace
|
|
-- or do nothing if there is no minimized windows on current workspace
|
|
withLastMinimized :: (Window -> X ()) -> X ()
|
|
withLastMinimized action = withLastMinimized' (flip whenJust action)
|
|
|
|
-- | Like withLastMinimized but the provided action is always invoked with a
|
|
-- 'Maybe Window', that will be nothing if there is no last minimized window.
|
|
withLastMinimized' :: (Maybe Window -> X ()) -> X ()
|
|
withLastMinimized' action = withMinimized (action . listToMaybe)
|
|
|
|
withMinimized :: ([Window] -> X a) -> X a
|
|
withMinimized action = do
|
|
minimized <- XS.gets minimizedStack
|
|
currentStack <- withWindowSet $ return . W.index
|
|
action $ minimized `L.intersect` currentStack
|