    --------------------------------------------------------------------------------
    -- |
    -- Module      :  Graphics.UI.GLUT.Begin
    -- Copyright   :  (c) Sven Panne 2002-2005
    -- License     :  BSD-style (see the file libraries/GLUT/LICENSE)
    --
    -- Maintainer  :  sven.panne@aedion.de
    -- Stability   :  stable
    -- Portability :  portable
    --
    -- After a GLUT program has done initial setup such as creating windows and
    -- menus, GLUT programs enter the GLUT event processing loop by calling
    -- 'mainLoop' or handle events iteratively with 'mainLoopEvent'.
    --
    --------------------------------------------------------------------------------

    module Graphics.UI.GLUT.Begin (
       -- * Handling events
       mainLoop, mainLoopEvent, leaveMainLoop,

       -- * Controlling the behaviour when windows are closed
       ActionOnWindowClose(..), actionOnWindowClose
    ) where

    import Foreign.C.Types ( CInt )
    import Graphics.Rendering.OpenGL.GL.StateVar ( StateVar, makeStateVar )
    import Graphics.UI.GLUT.Constants (
       glut_ACTION_ON_WINDOW_CLOSE, glut_ACTION_EXIT,
       glut_ACTION_GLUTMAINLOOP_RETURNS, glut_ACTION_CONTINUE_EXECUTION )
    import Graphics.UI.GLUT.QueryUtils ( simpleGet, glutSetOption )
    import Graphics.UI.GLUT.Extensions

    --------------------------------------------------------------------------------

    #include "HsGLUTExt.h"

    --------------------------------------------------------------------------------

    -- | Enter the GLUT event processing loop; it will call as necessary any
    -- callbacks that have been registered. This routine should be called at most
    -- once in a GLUT program.

    foreign import CALLCONV safe "glutMainLoop" mainLoop :: IO ()

    --------------------------------------------------------------------------------

    -- | (/freeglut only/) Process one iteration's worth of events in its event loop.
    -- This allows the application to control its own event loop and still use the
    -- GLUT package.

    mainLoopEvent :: IO ()
    mainLoopEvent = glutMainLoopEvent

    EXTENSION_ENTRY(safe,"freeglut",glutMainLoopEvent,IO ())

    --------------------------------------------------------------------------------

    -- | (/freeglut only/) Stop the event loop. If 'actionOnWindowClose' contains
    -- 'Exit', the application will exit; otherwise control will return to the
    -- function which called 'mainLoop'.
    --
    -- If the application has two nested calls to 'mainLoop' and calls
    -- 'leaveMainLoop', the behaviour is undefined. It may leave only the inner
    -- nested loop or it may leave both loops. If the reader has a strong preference
    -- for one behaviour over the other he should contact the freeglut Programming
    -- Consortium and ask for the code to be fixed.

    leaveMainLoop :: IO ()
    leaveMainLoop = glutLeaveMainLoop

    EXTENSION_ENTRY(safe,"freeglut",glutLeaveMainLoop,IO ())

    --------------------------------------------------------------------------------

    -- | The behaviour when the user closes a window.

    data ActionOnWindowClose
       = -- | Exit the whole program when any window is closed or 'leaveMainLoop'
         -- is called (default).
         Exit
       | -- | Return from mainLoop when any window is closed.
         MainLoopReturns
       | -- | Return from mainLoop after the last window is closed.
         ContinueExectuion
       deriving ( Eq, Ord, Show )

    marshalActionOnWindowClose :: ActionOnWindowClose -> CInt
    marshalActionOnWindowClose x = case x of
       Exit ->  glut_ACTION_EXIT
       MainLoopReturns -> glut_ACTION_GLUTMAINLOOP_RETURNS
       ContinueExectuion -> glut_ACTION_CONTINUE_EXECUTION

    unmarshalActionOnWindowClose :: CInt -> ActionOnWindowClose
    unmarshalActionOnWindowClose x
       | x == glut_ACTION_EXIT = Exit
       | x == glut_ACTION_GLUTMAINLOOP_RETURNS = MainLoopReturns
       | x == glut_ACTION_CONTINUE_EXECUTION = ContinueExectuion
       | otherwise = error ("unmarshalActionOnWindowClose: illegal value " ++ show x)

    -----------------------------------------------------------------------------

    -- | (/freeglut only/) Controls the behaviour when the user closes a window.

    actionOnWindowClose :: StateVar ActionOnWindowClose
    actionOnWindowClose =
       makeStateVar
          (simpleGet unmarshalActionOnWindowClose glut_ACTION_ON_WINDOW_CLOSE)
          (glutSetOption glut_ACTION_ON_WINDOW_CLOSE . marshalActionOnWindowClose)