-----------------------------------------------------------------------------
-- |
-- Module      :  XMonad.Util.Ungrab
-- Description :  Release xmonad's keyboard and pointer grabs immediately.
-- Copyright   :  (c) 2016 Brandon S Allbery
-- License     :  BSD-style (see xmonad/LICENSE)
--
-- Maintainer  :  allbery.b@gmail.com
-- Stability   :  unstable
-- Portability :  unportable
--
-- Allow releasing xmonad's keyboard grab
--
-----------------------------------------------------------------------------

module XMonad.Util.Ungrab
    ( -- * Usage:
      -- $usage
      unGrab
    ) where

import Graphics.X11.Xlib (sync)
import Graphics.X11.Xlib.Extras (currentTime)
import Graphics.X11.Xlib.Misc (ungrabKeyboard, ungrabPointer)
import XMonad.Core

-- $usage
-- Start a keyboard action with this if it is going to run something
-- that needs to do a keyboard, pointer, or server grab. For example,
--
-- > , ((modm .|. controlMask, xK_p), unGrab >> spawn "scrot")
--
-- (Other examples are screen lockers and "gksu".)
-- This avoids needing to insert a pause/sleep before running the
-- command.
--
-- xmonad retains the keyboard grab during key actions because if they
-- use a Submap, they need the keyboard to be grabbed, and if they had
-- to assert their own grab then the asynchronous nature of X11 allows
-- race conditions between xmonad, other clients, and the X server that
-- would cause keys to sometimes be "leaked" to the focused window.

-- | Release xmonad's keyboard grab, so other grabbers can do their thing.
unGrab :: X ()
unGrab :: X ()
unGrab = (Display -> X ()) -> X ()
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X ()) -> X ()) -> (Display -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \Display
d -> IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (Display -> Time -> IO ()
ungrabKeyboard Display
d Time
currentTime IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Display -> Time -> IO ()
ungrabPointer Display
d Time
currentTime IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Display -> Bool -> IO ()
sync Display
d Bool
False)