{-# LANGUAGE CPP #-}
{- |
   Module      :  System.Win32.Console.CtrlHandler
   Copyright   :  2008-2013 Judah Jacobson, 2013 shelarcy
   License     :  BSD-style

   Maintainer  :  shelarcy@gmail.com
   Stability   :  Provisional
   Portability :  Non-portable (Win32 API)

   Set handlers of console Ctrl events.
-}
module System.Win32.Console.CtrlHandler 
  ( CtrlEvent, Handler, PHANDLER_ROUTINE
  , withConsoleCtrlHandler
  , setConsoleCtrlHandler, c_SetConsoleCtrlHandler
  , mkHandler
  , cTRL_C_EVENT, cTRL_BREAK_EVENT
  ) where

import Control.Exception    ( bracket )
import Control.Monad        ( void )
import Foreign.Ptr          ( FunPtr )
import System.Win32.Console ( CtrlEvent, cTRL_C_EVENT, cTRL_BREAK_EVENT )
import System.Win32.Types   ( BOOL, failIfFalse_ )

#include "windows_cconv.h"

type Handler = CtrlEvent -> IO BOOL
-- type HandlerRoutine = Handler

type PHANDLER_ROUTINE = FunPtr Handler

withConsoleCtrlHandler :: Handler -> IO a -> IO a
withConsoleCtrlHandler :: forall a. Handler -> IO a -> IO a
withConsoleCtrlHandler Handler
handler IO a
io
  = IO PHANDLER_ROUTINE
-> (PHANDLER_ROUTINE -> IO ())
-> (PHANDLER_ROUTINE -> IO a)
-> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (do PHANDLER_ROUTINE
hd <- Handler -> IO PHANDLER_ROUTINE
mkHandler Handler
handler
                -- don't fail if we can't set the Ctrl-C handler

                -- for example, we might not be attached to a console?

                IO BOOL -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO BOOL -> IO ()) -> IO BOOL -> IO ()
forall a b. (a -> b) -> a -> b
$ PHANDLER_ROUTINE -> BOOL -> IO BOOL
c_SetConsoleCtrlHandler PHANDLER_ROUTINE
hd BOOL
True
                PHANDLER_ROUTINE -> IO PHANDLER_ROUTINE
forall (m :: * -> *) a. Monad m => a -> m a
return PHANDLER_ROUTINE
hd)
            (\PHANDLER_ROUTINE
hd -> IO BOOL -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO BOOL -> IO ()) -> IO BOOL -> IO ()
forall a b. (a -> b) -> a -> b
$ PHANDLER_ROUTINE -> BOOL -> IO BOOL
c_SetConsoleCtrlHandler PHANDLER_ROUTINE
hd BOOL
False)
            ((PHANDLER_ROUTINE -> IO a) -> IO a)
-> (PHANDLER_ROUTINE -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ IO a -> PHANDLER_ROUTINE -> IO a
forall a b. a -> b -> a
const IO a
io

-- | This function isn't suitable when we want to set the cTRL_C_EVENT handler.

-- If you want to set the cTRL_C_EVENT handler, use 'c_SetConsoleCtrlHandler' instead.

setConsoleCtrlHandler :: PHANDLER_ROUTINE -> BOOL -> IO ()
setConsoleCtrlHandler :: PHANDLER_ROUTINE -> BOOL -> IO ()
setConsoleCtrlHandler PHANDLER_ROUTINE
handler BOOL
flag
  = String -> IO BOOL -> IO ()
failIfFalse_ String
"SetConsoleCtrlHandler"
      (IO BOOL -> IO ()) -> IO BOOL -> IO ()
forall a b. (a -> b) -> a -> b
$ PHANDLER_ROUTINE -> BOOL -> IO BOOL
c_SetConsoleCtrlHandler PHANDLER_ROUTINE
handler BOOL
flag

foreign import WINDOWS_CCONV "wrapper" mkHandler :: Handler -> IO PHANDLER_ROUTINE
foreign import WINDOWS_CCONV "windows.h SetConsoleCtrlHandler"
  c_SetConsoleCtrlHandler :: PHANDLER_ROUTINE -> BOOL -> IO BOOL