|
|
{-# 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 def { 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
|