{-# LANGUAGE MultiParamTypeClasses, DeriveDataTypeable, TypeSynonymInstances, FlexibleContexts, PatternGuards #-} ---------------------------------------------------------------------------- -- | -- Module : XMonad.Layout.Minimize -- Copyright : (c) Jan Vornberger 2009, Alejandro Serrano 2010 -- License : BSD3-style (see LICENSE) -- -- Maintainer : jan.vornberger@informatik.uni-oldenburg.de -- Stability : unstable -- Portability : not portable -- -- Makes it possible to minimize windows, temporarily removing them -- from the layout until they are restored. -- ----------------------------------------------------------------------------- module XMonad.Layout.Minimize ( -- * Usage -- $usage minimize, minimizeWindow, MinimizeMsg(RestoreMinimizedWin,RestoreNextMinimizedWin), Minimize, ) where import XMonad import qualified XMonad.StackSet as W import XMonad.Layout.LayoutModifier import XMonad.Layout.BoringWindows as BW import XMonad.Util.WindowProperties (getProp32) import Data.List import qualified Data.Map as M import Data.Maybe import Foreign.C.Types (CLong) -- $usage -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@: -- -- > import XMonad.Layout.Minimize -- -- Then edit your @layoutHook@ by adding the Minimize layout modifier: -- -- > myLayout = minimize (Tall 1 (3/100) (1/2)) ||| Full ||| etc.. -- > main = xmonad defaultConfig { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: -- -- "XMonad.Doc.Extending#Editing_the_layout_hook" -- -- In the key-bindings, do something like: -- -- > , ((modm, xK_m ), withFocused minimizeWindow) -- > , ((modm .|. shiftMask, xK_m ), sendMessage RestoreNextMinimizedWin) -- -- The first action will minimize the focused window, while the second one will restore -- the next minimized window. -- -- For detailed instruction on editing the key binding see: -- -- "XMonad.Doc.Extending#Editing_key_bindings". -- -- The module is designed to work together with "XMonad.Layout.BoringWindows" so -- that minimized windows will be skipped over when switching the focused window with -- the keyboard. Include 'BW.boringWindows' in your layout hook and see the -- documentation of "XMonad.Layout.BoringWindows" on how to modify your keybindings. -- -- Also see "XMonad.Hooks.Minimize" if you want to be able to minimize -- and restore windows from your taskbar. data Minimize a = Minimize [Window] (M.Map Window W.RationalRect) deriving ( Read, Show ) minimize :: LayoutClass l Window => l Window -> ModifiedLayout Minimize l Window minimize = ModifiedLayout $ Minimize [] M.empty data MinimizeMsg = MinimizeWin Window | RestoreMinimizedWin Window | RestoreNextMinimizedWin deriving (Typeable, Eq) instance Message MinimizeMsg minimizeWindow :: Window -> X () minimizeWindow w = sendMessage (MinimizeWin w) >> BW.focusDown setMinimizedState :: Window -> Int -> (CLong -> [CLong] -> [CLong]) -> X () setMinimizedState win st f = do setWMState win st withDisplay $ \dpy -> do wm_state <- getAtom "_NET_WM_STATE" mini <- getAtom "_NET_WM_STATE_HIDDEN" wstate <- fromMaybe [] `fmap` getProp32 wm_state win let ptype = 4 -- The atom property type for changeProperty fi_mini = fromIntegral mini io $ changeProperty32 dpy win wm_state ptype propModeReplace (f fi_mini wstate) setMinimized :: Window -> X () setMinimized win = setMinimizedState win iconicState (:) setNotMinimized :: Window -> X () setNotMinimized win = setMinimizedState win normalState delete instance LayoutModifier Minimize Window where modifierDescription _ = "Minimize" modifyLayout (Minimize minimized _) wksp rect = do let stack = W.stack wksp filtStack = stack >>=W.filter (\w -> not (w `elem` minimized)) runLayout (wksp {W.stack = filtStack}) rect handleMess (Minimize minimized unfloated) m | Just (MinimizeWin w) <- fromMessage m, not (w `elem` minimized) = do setMinimized w ws <- gets windowset case M.lookup w (W.floating ws) of Nothing -> return $ Just $ Minimize (w:minimized) unfloated Just r -> do modify (\s -> s { windowset = W.sink w ws}) return $ Just $ Minimize (w:minimized) (M.insert w r unfloated) | Just (RestoreMinimizedWin w) <- fromMessage m = do setNotMinimized w case M.lookup w unfloated of Nothing -> return $ Just $ Minimize (minimized \\ [w]) unfloated Just r -> do ws <- gets windowset modify (\s -> s { windowset = W.float w r ws}) return $ Just $ Minimize (minimized \\ [w]) (M.delete w unfloated) | Just RestoreNextMinimizedWin <- fromMessage m = do ws <- gets windowset if not (null minimized) then case M.lookup (head minimized) unfloated of Nothing -> do let w = head minimized setNotMinimized w modify (\s -> s { windowset = W.focusWindow w ws}) return $ Just $ Minimize (tail minimized) unfloated Just r -> do let w = head minimized setNotMinimized w modify (\s -> s { windowset = (W.focusWindow w . W.float w r) ws}) return $ Just $ Minimize (tail minimized) (M.delete w unfloated) else return Nothing | Just BW.UpdateBoring <- fromMessage m = do ws <- gets (W.workspace . W.current . windowset) flip sendMessageWithNoRefresh ws $ BW.Replace "Minimize" minimized return Nothing | otherwise = return Nothing