    -----------------------------------------------------------------------------
    -- |
    -- Module      :  XMonad.Util.Replace
    -- Description :  Implements a @--replace@ flag outside of core.
    -- Copyright   :  (c) Jan Vornberger 2009
    -- License     :  BSD3-style (see LICENSE)
    --
    -- Maintainer  :  Adam Vogt <vogt.adam@gmail.com>
    -- Stability   :  unstable
    -- Portability :  unportable
    --
    -- Implements a @--replace@ behavior outside of core.
    --
    -----------------------------------------------------------------------------

    -- refer to core patches:
    -- http://article.gmane.org/gmane.comp.lang.haskell.xmonad/8358
    module XMonad.Util.Replace
        ( -- * Usage
          -- $usage
          replace

          -- * Notes
          -- $shortcomings

          -- ** Implementing a @--replace@ flag
          -- $getArgs
        ) where

    import XMonad
    import XMonad.Prelude

    -- $usage
    -- You must run the 'replace' action before starting xmonad proper, this
    -- results in xmonad replacing the currently running WM regardless of the
    -- arguments it is run with:
    --
    -- > import XMonad
    -- > import XMonad.Util.Replace
    -- > main = do
    -- >    replace
    -- >    xmonad $ def { .... }
    --

    -- $shortcomings
    -- This doesn't seem to work for replacing WMs that have been started
    -- from within xmonad, such as with @'restart' "openbox" False@, but no other
    -- WMs that implements --replace manage this either. 'replace' works for
    -- replacing metacity when the full gnome-session is started at least.

    -- $getArgs
    -- You can use 'System.Environment.getArgs' to watch for an explicit
    -- @--replace@ flag:
    --
    -- > import XMonad
    -- > import XMonad.Util.Replace (replace)
    -- > import Control.Monad (when)
    -- > import System.Environment (getArgs)
    -- >
    -- > main = do
    -- >    args <- getArgs
    -- >    when ("--replace" `elem` args) replace
    -- >    xmonad $ def { .... }
    --
    --
    -- Note that your @~\/.xmonad/xmonad-$arch-$os@ binary is not run with the same
    -- flags as the @xmonad@ binary that calls it. You may be able to work around
    -- this by running your @~\/.xmonad/xmonad-$arch-$os@ binary directly, which is
    -- otherwise not recommended.

    -- | @replace@ must be run before xmonad starts to signals to compliant window
    -- managers that they must exit and let xmonad take over.
    replace :: IO ()
    replace :: IO ()
    replace = do
        dpy   <- String -> IO Display
    openDisplay String
    ""
        let dflt = Display -> ScreenNumber
    defaultScreen Display
    dpy

        rootw  <- rootWindow dpy dflt

        -- check for other WM
        wmSnAtom <- internAtom dpy ("WM_S" ++ show dflt) False
        currentWmSnOwner <- xGetSelectionOwner dpy wmSnAtom
        when (currentWmSnOwner /= 0) $ do
            putStrLn $ "Screen " ++ show dflt ++ " on display \""
                        ++ displayString dpy ++ "\" already has a window manager."

            -- prepare to receive destroyNotify for old WM
            selectInput dpy currentWmSnOwner structureNotifyMask

            -- create off-screen window
            netWmSnOwner <- allocaSetWindowAttributes $ \Ptr SetWindowAttributes
    attributes -> do
                Ptr SetWindowAttributes -> Bool -> IO ()
    set_override_redirect Ptr SetWindowAttributes
    attributes Bool
    True
                Ptr SetWindowAttributes -> Window -> IO ()
    set_event_mask Ptr SetWindowAttributes
    attributes Window
    propertyChangeMask
                let screen :: Screen
    screen = Display -> Screen
    defaultScreenOfDisplay Display
    dpy
                let visual :: Visual
    visual = Screen -> Visual
    defaultVisualOfScreen Screen
    screen
                let attrmask :: Window
    attrmask = Window
    cWOverrideRedirect Window -> Window -> Window
    forall a. Bits a => a -> a -> a
    .|. Window
    cWEventMask
                Display
    -> Window
    -> Position
    -> Position
    -> ScreenNumber
    -> ScreenNumber
    -> CInt
    -> CInt
    -> CInt
    -> Visual
    -> Window
    -> Ptr SetWindowAttributes
    -> IO Window
    createWindow Display
    dpy Window
    rootw (-Position
    100) (-Position
    100) ScreenNumber
    1 ScreenNumber
    1 CInt
    0 CInt
    copyFromParent CInt
    copyFromParent Visual
    visual Window
    attrmask Ptr SetWindowAttributes
    attributes

            -- try to acquire wmSnAtom, this should signal the old WM to terminate
            putStrLn "Replacing existing window manager..."
            xSetSelectionOwner dpy wmSnAtom netWmSnOwner currentTime

            -- SKIPPED: check if we acquired the selection
            -- SKIPPED: send client message indicating that we are now the WM

            -- wait for old WM to go away
            putStr "Waiting for other window manager to terminate... "
            fix $ \IO ()
    again -> do
                evt <- (XEventPtr -> IO ScreenNumber) -> IO ScreenNumber
    forall a. (XEventPtr -> IO a) -> IO a
    allocaXEvent ((XEventPtr -> IO ScreenNumber) -> IO ScreenNumber)
    -> (XEventPtr -> IO ScreenNumber) -> IO ScreenNumber
    forall a b. (a -> b) -> a -> b
    $ \XEventPtr
    event -> do
                    Display -> Window -> Window -> XEventPtr -> IO ()
    windowEvent Display
    dpy Window
    currentWmSnOwner Window
    structureNotifyMask XEventPtr
    event
                    XEventPtr -> IO ScreenNumber
    get_EventType XEventPtr
    event

                when (evt /= destroyNotify) again
            putStrLn "done"
        closeDisplay dpy