content: {-# LANGUAGE DeriveDataTypeable #-}
  
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  XMonad.Hooks.ManageDebug
  -- Copyright   :  (c) Brandon S Allbery KF8NH, 2014
  -- License     :  BSD3-style (see LICENSE)
  --
  -- Maintainer  :  allbery.b@gmail.com
  -- Stability   :  unstable
  -- Portability :  not portable
  --
  -- A @manageHook@ and associated @logHook@ for debugging 'ManageHook's.
  -- Simplest usage: wrap your xmonad config in the @debugManageHook@ combinator.
  -- Or use @debugManageHookOn@ for a triggerable version, specifying the
  -- triggering key sequence in 'XMonad.Util.EZConfig' syntax. Or use the
  -- individual hooks in whatever way you see fit.
  --
  -----------------------------------------------------------------------------
  --
  --
  
  module XMonad.Hooks.ManageDebug (debugManageHook
                                  ,debugManageHookOn
                                  ,manageDebug
                                  ,maybeManageDebug
                                  ,manageDebugLogHook
                                  ,debugNextManagedWindow
                                  ) where
  
  import           XMonad
  import           XMonad.Hooks.DebugStack
  import           XMonad.Util.DebugWindow
  import           XMonad.Util.EZConfig
  import qualified XMonad.Util.ExtensibleState                                                 as XS
  import           Control.Monad                            (when)
  
  -- persistent state for manageHook debugging to trigger logHook debugging
  data ManageStackDebug = MSD (Bool,Bool) deriving Typeable
  instance ExtensionClass ManageStackDebug where
    initialValue = MSD (False,False)
  
  -- | A combinator to add full 'ManageHook' debugging in a single operation.
  debugManageHook :: XConfig l -> XConfig l
  debugManageHook cf = cf {logHook    = manageDebugLogHook <+> logHook    cf
                          ,manageHook = manageDebug        <+> manageHook cf
                          }
  
  -- | A combinator to add triggerable 'ManageHook' debugging in a single operation.
  --   Specify a key sequence as a string in 'XMonad.Util.EZConfig' syntax; press
  --   this key before opening the window to get just that logged.
  debugManageHookOn :: String -> XConfig l -> XConfig l
  debugManageHookOn key cf = cf {logHook    = manageDebugLogHook <+> logHook    cf
                                ,manageHook = maybeManageDebug   <+> manageHook cf
                                }
                             `additionalKeysP`
                             [(key,debugNextManagedWindow)]
  
  -- | Place this at the start of a 'ManageHook', or possibly other places for a
  --   more limited view. It will show the current 'StackSet' state and the new
  --   window, and set a flag so that @manageDebugLogHook@ will display the
  --   final 'StackSet' state.
  --
  --   Note that the initial state shows only the current workspace; the final
  --   one shows all workspaces, since your 'ManageHook' might use e.g. 'doShift',
  manageDebug :: ManageHook
  manageDebug = do
    w <- ask
    liftX $ do
      trace "== manageHook; current stack =="
      debugStackString >>= trace
      ws <- debugWindow w
      trace $ "new:\n  " ++ ws
      XS.modify $ \(MSD (_,key)) -> MSD (True,key)
    idHook
  
  -- | @manageDebug@ only if the user requested it with @debugNextManagedWindow@.
  maybeManageDebug :: ManageHook
  maybeManageDebug = do
    go <- liftX $ do
      MSD (log_,go') <- XS.get
      XS.put $ MSD (log_,False)
      return go'
    if go then manageDebug else idHook
  
  -- | If @manageDebug@ has set the debug-stack flag, show the stack.
  manageDebugLogHook :: X ()
  manageDebugLogHook = do
                         MSD (go,key) <- XS.get
                         when go $ do
                           trace "== manageHook; final stack =="
                           debugStackFullString >>= trace
                           XS.put $ MSD (False,key)
                         idHook
  
  -- | Request that the next window to be managed be @manageDebug@-ed. This can
  --   be used anywhere an X action can, such as key bindings, mouse bindings
  --   (presumably with 'const'), 'startupHook', etc.
  debugNextManagedWindow :: X ()
  debugNextManagedWindow = XS.modify $ \(MSD (log_,_)) -> MSD (log_,True)
  