    {-# LANGUAGE ScopedTypeVariables,DeriveDataTypeable #-}

    {-# LINE 2 "./System/Glib/GError.chs" #-}
    -- -*-haskell-*-
    -- GIMP Toolkit (GTK) GError API
    --
    -- Author : Duncan Coutts
    --
    -- Created: 2 July 2004
    --
    -- Copyright (C) 2004 Duncan Coutts
    -- parts derived from Structs.hsc Copyright (c) 1999..2002 Axel Simon
    --
    -- This library is free software; you can redistribute it and/or
    -- modify it under the terms of the GNU Lesser General Public
    -- License as published by the Free Software Foundation; either
    -- version 2.1 of the License, or (at your option) any later version.
    --
    -- This library is distributed in the hope that it will be useful,
    -- but WITHOUT ANY WARRANTY; without even the implied warranty of
    -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    -- Lesser General Public License for more details.
    --
    -- |
    -- Maintainer : gtk2hs-users@lists.sourceforge.net
    -- Stability : provisional
    -- Portability : portable (depends on GHC)
    --
    -- Error Reporting, glib's system for reporting errors.
    --
    -- 'GError's are used by glib to report recoverable runtime errors.
    --
    -- This module provides functions for checking glib\/gtk functions that report
    -- 'GError's. It also provides functions for throwing and catching 'GError's as
    -- Haskell exceptions.
    --
    module System.Glib.GError (

      -- * Data types
      --
      GError(..),
      GErrorDomain,
      GErrorCode,
      GErrorMessage,

      -- * Catching GError exceptions
      -- | To catch GError exceptions thrown by Gtk2Hs functions use the
      -- catchGError* or handleGError* functions. They work in a similar way to
      -- the standard 'Control.Exception.catch' and 'Control.Exception.handle'
      -- functions.
      --
      -- 'catchGError' \/ 'handleGError' catches all GError exceptions, you provide
      -- a handler function that gets given the GError if an exception was thrown.
      -- This is the most general but is probably not what you want most of the
      -- time. It just gives you the raw error code rather than a Haskell
      -- enumeration of the error codes. Most of the time you will only want to
      -- catch a specific error or any error from a specific error domain. To
      -- catch just a single specific error use
      -- 'catchGErrorJust' \/ 'handleGErrorJust'. To catch any error in a
      -- particular error domain use 'catchGErrorJustDomain' \/
      -- 'handleGErrorJustDomain'
      --
      catchGErrorJust,
      catchGErrorJustDomain,

      handleGErrorJust,
      handleGErrorJustDomain,

      -- ** Deprecated
      catchGError,
      handleGError,
      failOnGError,
      throwGError,

      -- * Checking for GErrors returned by glib\/gtk functions
      -- | * Note, these functions are only useful to implementors
      --
      -- If you are wrapping a new API that reports 'GError's you should probably
      -- use 'propagateGError' to convert the GError into an exception. You should
      -- also note in the documentation for the function that it throws GError
      -- exceptions and the Haskell enumeration for the expected glib GError
      -- domain(s), so that users know what exceptions they might want to catch.
      --
      -- If you think it is more appropriate to use an alternate return value (eg
      -- Either\/Maybe) then you should use 'checkGError'.

      GErrorClass(..),
      propagateGError,
      checkGError
      ) where

    import Foreign
    import Foreign.C
    import System.Glib.UTFString
    import Control.Exception
    import Data.Typeable
    import Prelude hiding (catch)

    -- | A GError consists of a domain, code and a human readable message.
    data GError = GError !GErrorDomain !GErrorCode !GErrorMessage
      deriving Typeable

    instance Show GError where
      show (GError _ _ msg) = msg

    instance Exception GError

    type GQuark = (CUInt)
    {-# LINE 108 "./System/Glib/GError.chs" #-}

    -- | A code used to identify the \'namespace\' of the error. Within each error
    -- domain all the error codes are defined in an enumeration. Each gtk\/gnome
    -- module that uses GErrors has its own error domain. The rationale behind
    -- using error domains is so that each module can organise its own error codes
    -- without having to coordinate on a global error code list.
    type GErrorDomain = GQuark

    -- | A code to identify a specific error within a given 'GErrorDomain'. Most of
    -- time you will not need to deal with this raw code since there is an
    -- enumeration type for each error domain. Of course which enumeraton to use
    -- depends on the error domain, but if you use 'catchGErrorJustDomain' or
    -- 'handleGErrorJustDomain', this is worked out for you automatically.
    type GErrorCode = Int

    -- | A human readable error message.
    type GErrorMessage = String

    instance Storable GError where
      sizeOf _ = 12
    {-# LINE 128 "./System/Glib/GError.chs" #-}
      alignment _ = alignment (undefined:: GQuark)
      peek ptr = do
        (domain :: GQuark) <- (\ptr -> do {peekByteOff ptr 0 ::IO CUInt}) ptr
        (code :: (CInt)) <- (\ptr -> do {peekByteOff ptr 4 ::IO CInt}) ptr
        (msgPtr :: CString) <- (\ptr -> do {peekByteOff ptr 8 ::IO (Ptr CChar)}) ptr
        msg <- peekUTFString msgPtr
        return $ GError (fromIntegral domain) (fromIntegral code) msg
      poke _ = error "GError::poke: not implemented"

    -- | Each error domain's error enumeration type should be an instance of this
    -- class. This class helps to hide the raw error and domain codes from the
    -- user. This interface should be implemented by calling the approrpiate
    -- @{error_domain}_error_quark@. It is safe to use a pure FFI call for this.
    --
    -- Example for 'Graphics.UI.Gtk.Gdk.Pixbuf.PixbufError':
    --
    -- > instance GErrorClass PixbufError where
    -- > gerrorDomain _ = {#call pure unsafe pixbuf_error_quark#}
    --
    class Enum err => GErrorClass err where
      gerrorDomain :: err -> GErrorDomain -- ^ This must not use the value of its
                                          -- parameter so that it is safe to pass
              -- 'undefined'.

    -- | Glib functions which report 'GError's take as a parameter a @GError
    -- **error@. Use this function to supply such a parameter. It checks if an
    -- error was reported and if so throws it as a Haskell exception.
    --
    -- Example of use:
    --
    -- > propagateGError $ \gerrorPtr ->
    -- > {# call g_some_function_that_might_return_an_error #} a b gerrorPtr
    --
    propagateGError :: (Ptr (Ptr ()) -> IO a) -> IO a
    propagateGError action = checkGError action throwGError

    -- | Like 'propagateGError' but instead of throwing the GError as an exception
    -- handles the error immediately using the supplied error handler.
    --
    -- Example of use:
    --
    -- > checkGError
    -- > (\gerrorPtr -> {# call g_some_function_that_might_return_an_error #} a b gerrorPtr)
    -- > (\(GError domain code msg) -> ...)
    --
    checkGError :: (Ptr (Ptr ()) -> IO a) -> (GError -> IO a) -> IO a
    checkGError action handler =
      alloca $ \(errPtrPtr :: Ptr (Ptr GError)) -> do
      poke errPtrPtr nullPtr
      result <- action (castPtr errPtrPtr)
      errPtr <- peek errPtrPtr
      if errPtr == nullPtr
        then return result
        else do gerror <- peek errPtr
                g_error_free (castPtr errPtr)
                handler gerror

    -- | Use this if you need to explicitly throw a GError or re-throw an existing
    -- GError that you do not wish to handle.
    throwGError :: GError -> IO a
    throwGError = throw
    {-# DEPRECATED throwGError "Use ordinary Control.Exception.throw" #-}

    -- | This will catch any GError exception. The handler function will receive the
    -- raw GError. This is probably only useful when you want to take some action
    -- that does not depend on which GError exception has occured, otherwise it
    -- would be better to use either 'catchGErrorJust' or 'catchGErrorJustDomain'.
    -- For example:
    --
    -- > catchGError
    -- > (do ...
    -- > ...)
    -- > (\(GError dom code msg) -> fail msg)
    --
    catchGError :: IO a -- ^ The computation to run
                -> (GError -> IO a) -- ^ Handler to invoke if an exception is raised
                -> IO a
    catchGError = catch
    {-# DEPRECATED catchGError "Use ordinary Control.Exception.catch" #-}

    -- | This will catch just a specific GError exception. If you need to catch a
    -- range of related errors, 'catchGErrorJustDomain' is probably more
    -- appropriate. Example:
    --
    -- > do image <- catchGErrorJust PixbufErrorCorruptImage
    -- > loadImage
    -- > (\errorMessage -> do log errorMessage
    -- > return mssingImagePlaceholder)
    --
    catchGErrorJust :: GErrorClass err => err -- ^ The error to catch
                    -> IO a -- ^ The computation to run
                    -> (GErrorMessage -> IO a) -- ^ Handler to invoke if an exception is raised
                    -> IO a
    catchGErrorJust code action handler = catch action handler'
      where handler' gerror@(GError domain code' msg)
              | fromIntegral domain == gerrorDomain code
               && code' == fromEnum code   = handler msg
              | otherwise = throw gerror

    -- | Catch all GErrors from a particular error domain. The handler function
    -- should just deal with one error enumeration type. If you need to catch
    -- errors from more than one error domain, use this function twice with an
    -- appropriate handler functions for each.
    --
    -- > catchGErrorJustDomain
    -- > loadImage
    -- > (\err message -> case err of
    -- > PixbufErrorCorruptImage -> ...
    -- > PixbufErrorInsufficientMemory -> ...
    -- > PixbufErrorUnknownType -> ...
    -- > _ -> ...)
    --
    catchGErrorJustDomain :: GErrorClass err => IO a -- ^ The computation to run
                          -> (err -> GErrorMessage -> IO a) -- ^ Handler to invoke if an exception is raised
                          -> IO a
    catchGErrorJustDomain action (handler :: err -> GErrorMessage -> IO a) =
        catch action handler'
      where handler' gerror@(GError domain code msg)
              | fromIntegral domain == gerrorDomain (undefined::err) = handler (toEnum code) msg
              | otherwise = throwGError gerror

    -- | A verson of 'catchGError' with the arguments swapped around.
    --
    -- > handleGError (\(GError dom code msg) -> ...) $
    -- > ...
    --
    handleGError :: (GError -> IO a) -> IO a -> IO a
    handleGError = handle
    {-# DEPRECATED handleGError "Use ordinary Control.Exception.handle" #-}

    -- | A verson of 'handleGErrorJust' with the arguments swapped around.
    handleGErrorJust :: GErrorClass err => err -> (GErrorMessage -> IO a) -> IO a -> IO a
    handleGErrorJust code = flip (catchGErrorJust code)

    -- | A verson of 'catchGErrorJustDomain' with the arguments swapped around.
    handleGErrorJustDomain :: GErrorClass err => (err -> GErrorMessage -> IO a) -> IO a -> IO a
    handleGErrorJustDomain = flip catchGErrorJustDomain

    -- | Catch all GError exceptions and convert them into a general failure.
    failOnGError :: IO a -> IO a
    failOnGError action = catchGError action (\(GError dom code msg) -> fail msg)

    foreign import ccall unsafe "g_error_free"
      g_error_free :: ((Ptr ()) -> (IO ()))