mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-08-16 12:43:53 -07:00
123 lines
4.2 KiB
Haskell
123 lines
4.2 KiB
Haskell
-----------------------------------------------------------------------------
|
|
-- |
|
|
-- Module : XMonad.Hooks.DynamicHooks
|
|
-- Copyright : (c) Braden Shepherdson 2008
|
|
-- License : BSD-style (as xmonad)
|
|
--
|
|
-- Maintainer : Braden.Shepherdson@gmail.com
|
|
-- Stability : unstable
|
|
-- Portability : unportable
|
|
--
|
|
-- One-shot and permanent ManageHooks that can be updated at runtime.
|
|
--
|
|
-----------------------------------------------------------------------------
|
|
|
|
module XMonad.Hooks.DynamicHooks (
|
|
-- * Usage
|
|
-- $usage
|
|
initDynamicHooks
|
|
,dynamicMasterHook
|
|
,addDynamicHook
|
|
,updateDynamicHook
|
|
,oneShotHook
|
|
) where
|
|
|
|
import XMonad
|
|
import System.IO
|
|
|
|
import Data.List
|
|
import Data.Maybe (listToMaybe)
|
|
import Data.Monoid
|
|
import Data.IORef
|
|
|
|
-- $usage
|
|
-- Provides two new kinds of 'ManageHooks' that can be defined at runtime.
|
|
--
|
|
-- * One-shot 'ManageHooks' that are deleted after they execute.
|
|
--
|
|
-- * Permanent 'ManageHooks' (unless you want to destroy them)
|
|
--
|
|
-- Note that you will lose all dynamically defined 'ManageHook's when you @mod+q@!
|
|
-- If you want them to last, you should create them as normal in your @xmonad.hs@.
|
|
--
|
|
-- First, you must execute 'initDynamicHooks' from 'main' in your @xmonad.hs@:
|
|
--
|
|
-- > dynHooksRef <- initDynamicHooks
|
|
--
|
|
-- and then pass this value to the other functions in this module.
|
|
--
|
|
-- You also need to add the base 'ManageHook':
|
|
--
|
|
-- > xmonad { manageHook = myManageHook <+> dynamicMasterHook dynHooksRef }
|
|
--
|
|
-- You must include this @dynHooksRef@ value when using the functions in this
|
|
-- module:
|
|
--
|
|
-- > xmonad { keys = myKeys `Data.Map.union` Data.Map.fromList
|
|
-- > [((modMask conf, xK_i), oneShotHook dynHooksRef
|
|
-- > "FFlaunchHook" (className =? "firefox") (doShift "3")
|
|
-- > >> spawn "firefox")
|
|
-- > ,((modMask conf, xK_u), addDynamicHook dynHooksRef
|
|
-- > (className =? "example" --> doFloat))
|
|
-- > ,((modMask conf, xK_y), updatePermanentHook dynHooksRef
|
|
-- > (const idHook))) ] -- resets the permanent hook.
|
|
--
|
|
|
|
data DynamicHooks = DynamicHooks
|
|
{ transients :: [(Query Bool, ManageHook)]
|
|
, permanent :: ManageHook }
|
|
|
|
|
|
-- | Creates the 'IORef' that stores the dynamically created 'ManageHook's.
|
|
initDynamicHooks :: IO (IORef DynamicHooks)
|
|
initDynamicHooks = newIORef (DynamicHooks { transients = [],
|
|
permanent = idHook })
|
|
|
|
|
|
-- this hook is always executed, and the IORef's contents checked.
|
|
-- note that transient hooks are run second, therefore taking precedence
|
|
-- over permanent ones on matters such as which workspace to shift to.
|
|
-- doFloat and doIgnore are idempotent.
|
|
-- | Master 'ManageHook' that must be in your @xmonad.hs@ 'ManageHook'.
|
|
dynamicMasterHook :: IORef DynamicHooks -> ManageHook
|
|
dynamicMasterHook ref = return True -->
|
|
(ask >>= \w -> liftX (do
|
|
dh <- io $ readIORef ref
|
|
(Endo f) <- runQuery (permanent dh) w
|
|
ts <- mapM (\(q,a) -> runQuery q w >>= \x -> return (x,(q, a))) (transients dh)
|
|
let (ts',nts) = partition fst ts
|
|
gs <- mapM (flip runQuery w . snd . snd) ts'
|
|
let (Endo g) = maybe (Endo id) id $ listToMaybe gs
|
|
io $ writeIORef ref $ dh { transients = map snd nts }
|
|
return $ Endo $ f . g
|
|
))
|
|
|
|
-- | Appends the given 'ManageHook' to the permanent dynamic 'ManageHook'.
|
|
addDynamicHook :: IORef DynamicHooks -> ManageHook -> X ()
|
|
addDynamicHook ref m = updateDynamicHook ref (<+> m)
|
|
|
|
|
|
-- | Modifies the permanent 'ManageHook' with an arbitrary function.
|
|
updateDynamicHook :: IORef DynamicHooks -> (ManageHook -> ManageHook) -> X ()
|
|
updateDynamicHook ref f =
|
|
io $ modifyIORef ref $ \dh -> dh { permanent = f (permanent dh) }
|
|
|
|
|
|
-- | Creates a one-shot 'ManageHook'. Note that you have to specify the two
|
|
-- parts of the 'ManageHook' separately. Where you would usually write:
|
|
--
|
|
-- > className =? "example" --> doFloat
|
|
--
|
|
-- you must call 'oneShotHook' as
|
|
--
|
|
-- > oneShotHook dynHooksRef (className =? "example) doFloat
|
|
--
|
|
oneShotHook :: IORef DynamicHooks -> Query Bool -> ManageHook -> X ()
|
|
oneShotHook ref q a =
|
|
io $ modifyIORef ref
|
|
$ \dh -> dh { transients = (q,a):(transients dh) }
|
|
|
|
|
|
|
|
|