Pass VisualType to xine_open_video_driver

{-# LANGUAGE CPP #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE StandaloneDeriving #-}

-- |
-- Module      : Xine.Foreign
-- Copyright   : (c) Joachim Fasting 2010
-- License     : LGPL
-- Maintainer  : Joachim Fasting <joachim.fasting@gmail.com>
-- Stability   : unstable
-- Portability : not portable
--
-- A simple binding to xine-lib. Low-level bindings.

module Xine.Foreign (
    -- * Version information
    xine_get_version_string, xine_get_version, xine_check_version,
    -- * Global engine handling
    Engine, AudioPort, VideoPort, VisualType(..),
    xine_new, xine_init, xine_open_audio_driver, xine_open_video_driver,
    xine_close_audio_driver, xine_close_video_driver, xine_exit,
    -- * Stream handling
    Stream, StreamParam(..), Speed(..), NormalSpeed(..), Zoom(..),
    AspectRatio(..), Mrl, EngineParam(..),
    xine_stream_new, xine_open, xine_play, xine_stop, xine_close,
    xine_engine_set_param, xine_engine_get_param,
    xine_set_param, xine_get_param,
    -- * Information retrieval
    EngineStatus(..), XineError(..),
    xine_get_error, xine_get_status
    ) where

import Control.Monad (liftM)
import Foreign
import Foreign.C

#include <xine.h>

-- Define the name of the dynamic library that has to be loaded before any of
-- the external C functions may be invoked.
-- The prefix declaration allows us to refer to identifiers while omitting the
-- prefix. Prefix matching is case insensitive and any underscore characters
-- between the prefix and the stem of the identifiers are also removed.
{#context lib="xine" prefix="xine"#}

-- Opaque types used for structures that are never dereferenced on the
-- Haskell side.
{#pointer *xine_t as Engine foreign newtype#}
{#pointer *xine_audio_port_t as AudioPort foreign newtype#}
{#pointer *xine_video_port_t as VideoPort foreign newtype#}
{#pointer *xine_stream_t as Stream foreign newtype#}

newtype Data = Data (Ptr Data)

-- | Media Resource Locator.
type Mrl = String

------------------------------------------------------------------------------
-- Marshalling
------------------------------------------------------------------------------

int2bool = (/= 0)

cint2enum :: Enum a => CInt -> a
cint2enum = toEnum . fromIntegral

enum2cint :: Enum a => a -> CInt
enum2cint = fromIntegral . fromEnum

peekInt = liftM fromIntegral . peek

peekEngine = liftM Engine . newForeignPtr_

peekAudioPort = liftM AudioPort . newForeignPtr_

peekVideoPort = liftM VideoPort . newForeignPtr_

peekStream = liftM Stream . newForeignPtr_

withData f = f nullPtr

withMaybeString :: Maybe String -> (CString -> IO a) -> IO a
withMaybeString Nothing f  = f nullPtr
withMaybeString (Just s) f = withCString s f

------------------------------------------------------------------------------
-- Version information
------------------------------------------------------------------------------

-- | Get xine-lib version string.
--
-- Header declaration:
--
-- const char *xine_get_version_string (void)
{#fun pure xine_get_version_string {} -> `String' peekCString*#}

-- | Get version as a triple: major, minor, sub
--
-- Header declaration:
--
-- void xine_get_version (int *major, int *minor, int *sub)
{#fun pure xine_get_version
 {alloca- `Int' peekInt*,
  alloca- `Int' peekInt*,
  alloca- `Int' peekInt*} -> `()'#}

-- | Compare given version to xine-lib version (major, minor, sub).
--
-- Header declaration:
--
-- int xine_check_version (int major, int minor, int sub)
--
-- returns 1 if compatible, 0 otherwise.
{#fun pure xine_check_version
 {fromIntegral `Int',
  fromIntegral `Int',
  fromIntegral `Int'} -> `Bool' int2bool#}

------------------------------------------------------------------------------
-- Global engine handling
------------------------------------------------------------------------------

-- | Valid visual types
{#enum define VisualType {XINE_VISUAL_TYPE_NONE as None
                         ,XINE_VISUAL_TYPE_X11 as X11
                         ,XINE_VISUAL_TYPE_X11_2 as X11_2
                         ,XINE_VISUAL_TYPE_AA as AA
                         ,XINE_VISUAL_TYPE_FB as FB
                         ,XINE_VISUAL_TYPE_GTK as GTK
                         ,XINE_VISUAL_TYPE_DFB as DFB
                         ,XINE_VISUAL_TYPE_PM as PM
                         ,XINE_VISUAL_TYPE_DIRECTX as DirectX
                         ,XINE_VISUAL_TYPE_CACA as CACA
                         ,XINE_VISUAL_TYPE_MACOSX as MacOSX
                         ,XINE_VISUAL_TYPE_XCB as XCB
                         ,XINE_VISUAL_TYPE_RAW as Raw
                         }#}

-- | Pre-init the Xine engine.
--
-- Header declaration:
--
-- xine_t *xine_new (void)
{#fun unsafe xine_new {} -> `Engine' peekEngine*#}

-- | Post-init the Xine engine.
--
-- Header declaration:
--
-- void xine_init (xine_t *self)
{#fun unsafe xine_init {withEngine* `Engine'} -> `()'#}

-- | Initialise audio driver.
--
-- Header declaration:
--
-- xine_audio_port_t *xine_open_audio_driver (xine_t *self, const char *id,
--                        void *data)
--
-- id: identifier of the driver, may be NULL for auto-detection
--
-- data: special data struct for ui/driver communication
--
-- May return NULL if the driver failed to load.
{#fun unsafe xine_open_audio_driver
 {withEngine* `Engine'
 ,withMaybeString* `(Maybe String)'
 ,withData- `Data'} -> `AudioPort' peekAudioPort*#}

-- | Initialise video driver.
--
-- Header declaration:
--
-- xine_video_port_t *xine_open_video_driver (xine_t *self, const char *id,
--                        int visual, void *data)
--
-- id: identifier of the driver, may be NULL for auto-detection
--
-- data: special data struct for ui/driver communication
--
-- visual : video driver flavor selector
--
-- May return NULL if the driver failed to load.
{#fun unsafe xine_open_video_driver
 {withEngine* `Engine'
 ,withMaybeString* `(Maybe String)'
 ,enum2cint `VisualType'
 ,withData- `Data'} -> `VideoPort' peekVideoPort*#}

-- | Close audio port.
--
-- Header declaration:
--
-- void xine_close_audio_driver (xine_t *self, xine_audio_port_t *driver)
{#fun unsafe xine_close_audio_driver
 {withEngine* `Engine'
 ,withAudioPort* `AudioPort'} -> `()'#}

-- | Close video port.
--
-- Header declaration:
--
-- void xine_close_video_driver (xine_t *self, xine_video_port_t *driver)
{#fun unsafe xine_close_video_driver
 {withEngine* `Engine'
 ,withVideoPort* `VideoPort'} -> `()'#}

-- | Free all resources, close all plugins, close engine.
--
-- Header declaration:
--
-- void xine_exit (xine_t *self)
{#fun unsafe xine_exit {withEngine* `Engine'} -> `()'#}

------------------------------------------------------------------------------
-- Stream handling
------------------------------------------------------------------------------

-- | Engine parameter enumeration.
{#enum define EngineParam
           {XINE_ENGINE_PARAM_VERBOSITY as EngineVerbosity}#}

-- | Stream parameter enumeration.
{#enum define StreamParam
           {XINE_PARAM_SPEED as Speed
           ,XINE_PARAM_AV_OFFSET as AvOffset
           ,XINE_PARAM_AUDIO_CHANNEL_LOGICAL as AudioChannelLogical
           ,XINE_PARAM_SPU_CHANNEL as SpuChannel
           ,XINE_PARAM_AUDIO_VOLUME as AudioVolume
           ,XINE_PARAM_AUDIO_MUTE as AudioMute
           ,XINE_PARAM_AUDIO_COMPR_LEVEL as AudioComprLevel
           ,XINE_PARAM_AUDIO_REPORT_LEVEL as AudioReportLevel
           ,XINE_PARAM_VERBOSITY as Verbosity
           ,XINE_PARAM_SPU_OFFSET as SpuOffset
           ,XINE_PARAM_IGNORE_VIDEO as IgnoreVideo
           ,XINE_PARAM_IGNORE_AUDIO as IgnoreAudio
           ,XINE_PARAM_BROADCASTER_PORT as BroadcasterPort
           ,XINE_PARAM_METRONOM_PREBUFFER as MetronomPrebuffer
           ,XINE_PARAM_EQ_30HZ as Eq30Hz
           ,XINE_PARAM_EQ_60HZ as Eq60Hz
           ,XINE_PARAM_EQ_125HZ as Eq125Hz
           ,XINE_PARAM_EQ_500HZ as Eq500Hz
           ,XINE_PARAM_EQ_1000HZ as Eq1000Hz
           ,XINE_PARAM_EQ_2000HZ as Eq2000Hz
           ,XINE_PARAM_EQ_4000HZ as Eq4000Hz
           ,XINE_PARAM_EQ_8000HZ as Eq8000Hz
           ,XINE_PARAM_EQ_16000HZ as Eq16000Hz
           ,XINE_PARAM_AUDIO_CLOSE_DEVICE as AudioCloseDevice
           ,XINE_PARAM_AUDIO_AMP_MUTE as AmpMute
           ,XINE_PARAM_FINE_SPEED as FineSpeed
           ,XINE_PARAM_EARLY_FINISHED_EVENT as EarlyFinishedEvent
           ,XINE_PARAM_GAPLESS_SWITCH as GaplessSwitch
           ,XINE_PARAM_DELAY_FINISHED_EVENT as DelayFinishedEvent
           ,XINE_PARAM_VO_DEINTERLACE as Deinterlace
           ,XINE_PARAM_VO_ASPECT_RATIO as AspectRatio
           ,XINE_PARAM_VO_HUE as Hue
           ,XINE_PARAM_VO_SATURATION as Saturation
           ,XINE_PARAM_VO_CONTRAST as Contrast
           ,XINE_PARAM_VO_BRIGHTNESS as Brightness
           ,XINE_PARAM_VO_ZOOM_X as ZoomX
           ,XINE_PARAM_VO_ZOOM_Y as ZoomY
           ,XINE_PARAM_VO_PAN_SCAN as PanScan
           ,XINE_PARAM_VO_TVMODE as TvMode
           ,XINE_PARAM_VO_WINDOW_WIDTH as WindowWidth
           ,XINE_PARAM_VO_WINDOW_HEIGHT as WindowHeight
           ,XINE_PARAM_VO_CROP_LEFT as CropLeft
           ,XINE_PARAM_VO_CROP_RIGHT as CropRight
           ,XINE_PARAM_VO_CROP_TOP as CropTop
           ,XINE_PARAM_VO_CROP_BOTTOM as CropBottom
           }#}

-- | Values for XINE_PARAM_SPEED parameter.
{#enum define Speed
           {XINE_SPEED_PAUSE as Pause
           ,XINE_SPEED_SLOW_4 as Slow4
           ,XINE_SPEED_SLOW_2 as Slow2
           ,XINE_SPEED_NORMAL as Normal
           ,XINE_SPEED_FAST_2 as Fast2
           ,XINE_SPEED_FAST_4 as Fast4
           }#}

deriving instance Eq Speed

-- | Value for XINE_PARAM_FINE_SPEED
{#enum define NormalSpeed
           {XINE_FINE_SPEED_NORMAL as NormalSpeed}#}

-- | Values for XINE_PARAM_VO_ZOOM_
{#enum define Zoom
           {XINE_VO_ZOOM_STEP as ZoomStep
           ,XINE_VO_ZOOM_MAX as ZoomMax
           ,XINE_VO_ZOOM_MIN as ZoomMin}#}

-- | Values for XINE_PARAM_VO_ASPECT_RATIO
{#enum define AspectRatio
           {XINE_VO_ASPECT_AUTO as AspectAuto
           ,XINE_VO_ASPECT_SQUARE as AspectSquare
           ,XINE_VO_ASPECT_4_3 as Aspect43
           ,XINE_VO_ASPECT_ANAMORPHIC as AspectAnamorphic
           ,XINE_VO_ASPECT_DVB as AspectDvb
           ,XINE_VO_ASPECT_NUM_RATIOS as AspectNumRatios
           }#}

-- | Create a new stream for media playback.
--
-- Header declaration:
--
-- xine_stream_t *xine_stream_new (xine_t *self,
--     xine_audio_port *ao, xine_video_port_t *vo)
--
-- Returns xine_stream_t* if OK, NULL on error.
{#fun unsafe xine_stream_new
 {withEngine* `Engine'
 ,withAudioPort* `AudioPort'
 ,withVideoPort* `VideoPort'} -> `Stream' peekStream*#}

-- | Open a stream.
--
-- Header declaration:
--
-- int xine_open (xine_stream_t *stream, const char *mrl)
--
-- Returns 1 if OK, 0 on error.
{#fun unsafe xine_open
 {withStream* `Stream'
 ,withCAString* `Mrl'} -> `Int' fromIntegral#}

-- | Play a stream from a given position.
--
-- Header declaration:
--
-- int xine_play (xine_stream_t *stream, int start_pos, int start_time)
--
-- Returns 1 if OK, 0 on error.
{#fun unsafe xine_play
 {withStream* `Stream'
 ,fromIntegral `Int'
 ,fromIntegral `Int'} -> `Int' fromIntegral#}

-- | Stop stream playback.
-- The stream stays valid for new 'xine_open' or 'xine_play'.
--
-- Header declaration:
--
-- void xine_stop (xine_stream *stream)
{#fun unsafe xine_stop {withStream* `Stream'} -> `()'#}

-- | Free all stream-related resources.
-- The stream stays valid for new xine_open.
--
-- Header declaration:
--
-- void xine_close (xine_stream_t *stream)
{#fun unsafe xine_close {withStream* `Stream'} -> `()'#}

-- | Set engine parameter.
--
-- Header declaration:
--
-- void xine_engine_set_param (xine_t *self, int param, int value)
{#fun unsafe xine_engine_set_param
 {withEngine* `Engine'
 ,enum2cint `EngineParam'
 ,fromIntegral `Int'} -> `()'#}

-- | Get engine parameter.
--
-- Header declaration:
--
-- int xine_engine_get_param(xine_t *self, int param)
{#fun unsafe xine_engine_get_param
 {withEngine* `Engine'
 ,enum2cint `EngineParam'} -> `Int' fromIntegral#}

-- | Set stream parameter.
--
-- Header declaration:
--
-- void xine_set_param (xine_stream_t *stream, int param, int value)
{#fun unsafe xine_set_param
 `(Enum a)' =>
 {withStream* `Stream'
 ,enum2cint `StreamParam'
 ,enum2cint `a'} -> `()'#}

-- | Get stream parameter.
--
-- Header declaration:
--
-- int xine_get_param (xine_stream_t *stream, int param)
{#fun unsafe xine_get_param
 `(Enum a)' =>
 {withStream* `Stream'
 ,enum2cint `StreamParam'} -> `a' cint2enum#}

------------------------------------------------------------------------------
-- Information retrieval
------------------------------------------------------------------------------

-- | Engine status codes.
{#enum define EngineStatus
           {XINE_STATUS_IDLE as Idle
           ,XINE_STATUS_STOP as Stopped
           ,XINE_STATUS_PLAY as Playing
           ,XINE_STATUS_QUIT as Quitting}#}

-- | Xine error codes.
{#enum define XineError
           {XINE_ERROR_NONE as NoError
           ,XINE_ERROR_NO_INPUT_PLUGIN as NoInputPlugin
           ,XINE_ERROR_NO_DEMUX_PLUGIN as NoDemuxPlugin
           ,XINE_ERROR_MALFORMED_MRL as MalformedMrl
           ,XINE_ERROR_INPUT_FAILED as InputFailed}#}

-- | Return last error.
--
-- Header declaration:
--
-- int xine_get_error (xine_stream_t *stream)
{#fun unsafe xine_get_error
 {withStream* `Stream'} -> `XineError' cint2enum#}

-- | Get current xine engine status.
--
-- int xine_get_status (xine_stream_t *stream)
{#fun unsafe xine_get_status
 {withStream* `Stream'} -> `EngineStatus' cint2enum#}

{-# LANGUAGE CPP #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE StandaloneDeriving #-}

-- |
-- Module      : Xine.Foreign
-- Copyright   : (c) Joachim Fasting 2010
-- License     : LGPL
-- Maintainer  : Joachim Fasting <joachim.fasting@gmail.com>
-- Stability   : unstable
-- Portability : not portable
--
-- A simple binding to xine-lib. Low-level bindings.

module Xine.Foreign (
    -- * Version information
    xine_get_version_string, xine_get_version, xine_check_version,
    -- * Global engine handling
    Engine, AudioPort, VideoPort, VisualType(..),
    xine_new, xine_init, xine_open_audio_driver, xine_open_video_driver,
    xine_close_audio_driver, xine_close_video_driver, xine_exit,
    -- * Stream handling
    Stream, StreamParam(..), Speed(..), NormalSpeed(..), Zoom(..),
    AspectRatio(..), Mrl, EngineParam(..),
    xine_stream_new, xine_open, xine_play, xine_stop, xine_close,
    xine_engine_set_param, xine_engine_get_param,
    xine_set_param, xine_get_param,
    -- * Information retrieval
    EngineStatus(..), XineError(..),
    xine_get_error, xine_get_status
    ) where

import Control.Monad (liftM)
import Foreign
import Foreign.C

#include <xine.h>

-- Define the name of the dynamic library that has to be loaded before any of
-- the external C functions may be invoked.
-- The prefix declaration allows us to refer to identifiers while omitting the
-- prefix. Prefix matching is case insensitive and any underscore characters
-- between the prefix and the stem of the identifiers are also removed.
{#context lib="xine" prefix="xine"#}

-- Opaque types used for structures that are never dereferenced on the
-- Haskell side.
{#pointer *xine_t as Engine foreign newtype#}
{#pointer *xine_audio_port_t as AudioPort foreign newtype#}
{#pointer *xine_video_port_t as VideoPort foreign newtype#}
{#pointer *xine_stream_t as Stream foreign newtype#}

newtype Data = Data (Ptr Data)

-- | Media Resource Locator.
type Mrl = String

------------------------------------------------------------------------------
-- Marshalling
------------------------------------------------------------------------------

int2bool = (/= 0)

cint2enum :: Enum a => CInt -> a
cint2enum = toEnum . fromIntegral

enum2cint :: Enum a => a -> CInt
enum2cint = fromIntegral . fromEnum

peekInt = liftM fromIntegral . peek

peekEngine = liftM Engine . newForeignPtr_

peekAudioPort = liftM AudioPort . newForeignPtr_

peekVideoPort = liftM VideoPort . newForeignPtr_

peekStream = liftM Stream . newForeignPtr_

withData f = f nullPtr

withMaybeString :: Maybe String -> (CString -> IO a) -> IO a
withMaybeString Nothing f  = f nullPtr
withMaybeString (Just s) f = withCString s f

------------------------------------------------------------------------------
-- Version information
------------------------------------------------------------------------------

-- | Get xine-lib version string.
--
-- Header declaration:
--
-- const char *xine_get_version_string (void)
{#fun pure xine_get_version_string {} -> `String' peekCString*#}

-- | Get version as a triple: major, minor, sub
--
-- Header declaration:
--
-- void xine_get_version (int *major, int *minor, int *sub)
{#fun pure xine_get_version
 {alloca- `Int' peekInt*,
  alloca- `Int' peekInt*,
  alloca- `Int' peekInt*} -> `()'#}

-- | Compare given version to xine-lib version (major, minor, sub).
--
-- Header declaration:
--
-- int xine_check_version (int major, int minor, int sub)
--
-- returns 1 if compatible, 0 otherwise.
{#fun pure xine_check_version
 {fromIntegral `Int',
  fromIntegral `Int',
  fromIntegral `Int'} -> `Bool' int2bool#}

------------------------------------------------------------------------------
-- Global engine handling
------------------------------------------------------------------------------

-- | Valid visual types
{#enum define VisualType {XINE_VISUAL_TYPE_NONE as None
                         ,XINE_VISUAL_TYPE_X11 as X11
                         ,XINE_VISUAL_TYPE_X11_2 as X11_2
                         ,XINE_VISUAL_TYPE_AA as AA
                         ,XINE_VISUAL_TYPE_FB as FB
                         ,XINE_VISUAL_TYPE_GTK as GTK
                         ,XINE_VISUAL_TYPE_DFB as DFB
                         ,XINE_VISUAL_TYPE_PM as PM
                         ,XINE_VISUAL_TYPE_DIRECTX as DirectX
                         ,XINE_VISUAL_TYPE_CACA as CACA
                         ,XINE_VISUAL_TYPE_MACOSX as MacOSX
                         ,XINE_VISUAL_TYPE_XCB as XCB
                         ,XINE_VISUAL_TYPE_RAW as Raw
                         }#}

-- | Pre-init the Xine engine.
--
-- Header declaration:
--
-- xine_t *xine_new (void)
{#fun unsafe xine_new {} -> `Engine' peekEngine*#}

-- | Post-init the Xine engine.
--
-- Header declaration:
--
-- void xine_init (xine_t *self)
{#fun unsafe xine_init {withEngine* `Engine'} -> `()'#}

-- | Initialise audio driver.
--
-- Header declaration:
--
-- xine_audio_port_t *xine_open_audio_driver (xine_t *self, const char *id,
--                        void *data)
--
-- id: identifier of the driver, may be NULL for auto-detection
--
-- data: special data struct for ui/driver communication
--
-- May return NULL if the driver failed to load.
{#fun unsafe xine_open_audio_driver
 {withEngine* `Engine'
 ,withMaybeString* `(Maybe String)'
 ,withData- `Data'} -> `AudioPort' peekAudioPort*#}

-- | Initialise video driver.
--
-- Header declaration:
--
-- xine_video_port_t *xine_open_video_driver (xine_t *self, const char *id,
--                        int visual, void *data)
--
-- id: identifier of the driver, may be NULL for auto-detection
--
-- data: special data struct for ui/driver communication
--
-- visual : video driver flavor selector
--
-- May return NULL if the driver failed to load.
{#fun unsafe xine_open_video_driver
 {withEngine* `Engine'
 ,withMaybeString* `(Maybe String)'
 ,fromIntegral `Int'
 ,withData- `Data'} -> `VideoPort' peekVideoPort*#}

-- | Close audio port.
--
-- Header declaration:
--
-- void xine_close_audio_driver (xine_t *self, xine_audio_port_t *driver)
{#fun unsafe xine_close_audio_driver
 {withEngine* `Engine'
 ,withAudioPort* `AudioPort'} -> `()'#}

-- | Close video port.
--
-- Header declaration:
--
-- void xine_close_video_driver (xine_t *self, xine_video_port_t *driver)
{#fun unsafe xine_close_video_driver
 {withEngine* `Engine'
 ,withVideoPort* `VideoPort'} -> `()'#}

-- | Free all resources, close all plugins, close engine.
--
-- Header declaration:
--
-- void xine_exit (xine_t *self)
{#fun unsafe xine_exit {withEngine* `Engine'} -> `()'#}

------------------------------------------------------------------------------
-- Stream handling
------------------------------------------------------------------------------

-- | Engine parameter enumeration.
{#enum define EngineParam
           {XINE_ENGINE_PARAM_VERBOSITY as EngineVerbosity}#}

-- | Stream parameter enumeration.
{#enum define StreamParam
           {XINE_PARAM_SPEED as Speed
           ,XINE_PARAM_AV_OFFSET as AvOffset
           ,XINE_PARAM_AUDIO_CHANNEL_LOGICAL as AudioChannelLogical
           ,XINE_PARAM_SPU_CHANNEL as SpuChannel
           ,XINE_PARAM_AUDIO_VOLUME as AudioVolume
           ,XINE_PARAM_AUDIO_MUTE as AudioMute
           ,XINE_PARAM_AUDIO_COMPR_LEVEL as AudioComprLevel
           ,XINE_PARAM_AUDIO_REPORT_LEVEL as AudioReportLevel
           ,XINE_PARAM_VERBOSITY as Verbosity
           ,XINE_PARAM_SPU_OFFSET as SpuOffset
           ,XINE_PARAM_IGNORE_VIDEO as IgnoreVideo
           ,XINE_PARAM_IGNORE_AUDIO as IgnoreAudio
           ,XINE_PARAM_BROADCASTER_PORT as BroadcasterPort
           ,XINE_PARAM_METRONOM_PREBUFFER as MetronomPrebuffer
           ,XINE_PARAM_EQ_30HZ as Eq30Hz
           ,XINE_PARAM_EQ_60HZ as Eq60Hz
           ,XINE_PARAM_EQ_125HZ as Eq125Hz
           ,XINE_PARAM_EQ_500HZ as Eq500Hz
           ,XINE_PARAM_EQ_1000HZ as Eq1000Hz
           ,XINE_PARAM_EQ_2000HZ as Eq2000Hz
           ,XINE_PARAM_EQ_4000HZ as Eq4000Hz
           ,XINE_PARAM_EQ_8000HZ as Eq8000Hz
           ,XINE_PARAM_EQ_16000HZ as Eq16000Hz
           ,XINE_PARAM_AUDIO_CLOSE_DEVICE as AudioCloseDevice
           ,XINE_PARAM_AUDIO_AMP_MUTE as AmpMute
           ,XINE_PARAM_FINE_SPEED as FineSpeed
           ,XINE_PARAM_EARLY_FINISHED_EVENT as EarlyFinishedEvent
           ,XINE_PARAM_GAPLESS_SWITCH as GaplessSwitch
           ,XINE_PARAM_DELAY_FINISHED_EVENT as DelayFinishedEvent
           ,XINE_PARAM_VO_DEINTERLACE as Deinterlace
           ,XINE_PARAM_VO_ASPECT_RATIO as AspectRatio
           ,XINE_PARAM_VO_HUE as Hue
           ,XINE_PARAM_VO_SATURATION as Saturation
           ,XINE_PARAM_VO_CONTRAST as Contrast
           ,XINE_PARAM_VO_BRIGHTNESS as Brightness
           ,XINE_PARAM_VO_ZOOM_X as ZoomX
           ,XINE_PARAM_VO_ZOOM_Y as ZoomY
           ,XINE_PARAM_VO_PAN_SCAN as PanScan
           ,XINE_PARAM_VO_TVMODE as TvMode
           ,XINE_PARAM_VO_WINDOW_WIDTH as WindowWidth
           ,XINE_PARAM_VO_WINDOW_HEIGHT as WindowHeight
           ,XINE_PARAM_VO_CROP_LEFT as CropLeft
           ,XINE_PARAM_VO_CROP_RIGHT as CropRight
           ,XINE_PARAM_VO_CROP_TOP as CropTop
           ,XINE_PARAM_VO_CROP_BOTTOM as CropBottom
           }#}

-- | Values for XINE_PARAM_SPEED parameter.
{#enum define Speed
           {XINE_SPEED_PAUSE as Pause
           ,XINE_SPEED_SLOW_4 as Slow4
           ,XINE_SPEED_SLOW_2 as Slow2
           ,XINE_SPEED_NORMAL as Normal
           ,XINE_SPEED_FAST_2 as Fast2
           ,XINE_SPEED_FAST_4 as Fast4
           }#}

deriving instance Eq Speed

-- | Value for XINE_PARAM_FINE_SPEED
{#enum define NormalSpeed
           {XINE_FINE_SPEED_NORMAL as NormalSpeed}#}

-- | Values for XINE_PARAM_VO_ZOOM_
{#enum define Zoom
           {XINE_VO_ZOOM_STEP as ZoomStep
           ,XINE_VO_ZOOM_MAX as ZoomMax
           ,XINE_VO_ZOOM_MIN as ZoomMin}#}

-- | Values for XINE_PARAM_VO_ASPECT_RATIO
{#enum define AspectRatio
           {XINE_VO_ASPECT_AUTO as AspectAuto
           ,XINE_VO_ASPECT_SQUARE as AspectSquare
           ,XINE_VO_ASPECT_4_3 as Aspect43
           ,XINE_VO_ASPECT_ANAMORPHIC as AspectAnamorphic
           ,XINE_VO_ASPECT_DVB as AspectDvb
           ,XINE_VO_ASPECT_NUM_RATIOS as AspectNumRatios
           }#}

-- | Create a new stream for media playback.
--
-- Header declaration:
--
-- xine_stream_t *xine_stream_new (xine_t *self,
--     xine_audio_port *ao, xine_video_port_t *vo)
--
-- Returns xine_stream_t* if OK, NULL on error.
{#fun unsafe xine_stream_new
 {withEngine* `Engine'
 ,withAudioPort* `AudioPort'
 ,withVideoPort* `VideoPort'} -> `Stream' peekStream*#}

-- | Open a stream.
--
-- Header declaration:
--
-- int xine_open (xine_stream_t *stream, const char *mrl)
--
-- Returns 1 if OK, 0 on error.
{#fun unsafe xine_open
 {withStream* `Stream'
 ,withCAString* `Mrl'} -> `Int' fromIntegral#}

-- | Play a stream from a given position.
--
-- Header declaration:
--
-- int xine_play (xine_stream_t *stream, int start_pos, int start_time)
--
-- Returns 1 if OK, 0 on error.
{#fun unsafe xine_play
 {withStream* `Stream'
 ,fromIntegral `Int'
 ,fromIntegral `Int'} -> `Int' fromIntegral#}

-- | Stop stream playback.
-- The stream stays valid for new 'xine_open' or 'xine_play'.
--
-- Header declaration:
--
-- void xine_stop (xine_stream *stream)
{#fun unsafe xine_stop {withStream* `Stream'} -> `()'#}

-- | Free all stream-related resources.
-- The stream stays valid for new xine_open.
--
-- Header declaration:
--
-- void xine_close (xine_stream_t *stream)
{#fun unsafe xine_close {withStream* `Stream'} -> `()'#}

-- | Set engine parameter.
--
-- Header declaration:
--
-- void xine_engine_set_param (xine_t *self, int param, int value)
{#fun unsafe xine_engine_set_param
 {withEngine* `Engine'
 ,enum2cint `EngineParam'
 ,fromIntegral `Int'} -> `()'#}

-- | Get engine parameter.
--
-- Header declaration:
--
-- int xine_engine_get_param(xine_t *self, int param)
{#fun unsafe xine_engine_get_param
 {withEngine* `Engine'
 ,enum2cint `EngineParam'} -> `Int' fromIntegral#}

-- | Set stream parameter.
--
-- Header declaration:
--
-- void xine_set_param (xine_stream_t *stream, int param, int value)
{#fun unsafe xine_set_param
 `(Enum a)' =>
 {withStream* `Stream'
 ,enum2cint `StreamParam'
 ,enum2cint `a'} -> `()'#}

-- | Get stream parameter.
--
-- Header declaration:
--
-- int xine_get_param (xine_stream_t *stream, int param)
{#fun unsafe xine_get_param
 `(Enum a)' =>
 {withStream* `Stream'
 ,enum2cint `StreamParam'} -> `a' cint2enum#}

------------------------------------------------------------------------------
-- Information retrieval
------------------------------------------------------------------------------

-- | Engine status codes.
{#enum define EngineStatus
           {XINE_STATUS_IDLE as Idle
           ,XINE_STATUS_STOP as Stopped
           ,XINE_STATUS_PLAY as Playing
           ,XINE_STATUS_QUIT as Quitting}#}

-- | Xine error codes.
{#enum define XineError
           {XINE_ERROR_NONE as NoError
           ,XINE_ERROR_NO_INPUT_PLUGIN as NoInputPlugin
           ,XINE_ERROR_NO_DEMUX_PLUGIN as NoDemuxPlugin
           ,XINE_ERROR_MALFORMED_MRL as MalformedMrl
           ,XINE_ERROR_INPUT_FAILED as InputFailed}#}

-- | Return last error.
--
-- Header declaration:
--
-- int xine_get_error (xine_stream_t *stream)
{#fun unsafe xine_get_error
 {withStream* `Stream'} -> `XineError' cint2enum#}

-- | Get current xine engine status.
--
-- int xine_get_status (xine_stream_t *stream)
{#fun unsafe xine_get_status
 {withStream* `Stream'} -> `EngineStatus' cint2enum#}


sourceBufferSet/GetLanguage should pass/return 'Maybe SourceLanguage'.

{-# LANGUAGE CPP #-}
-- -*-haskell-*-
--  GIMP Toolkit (GTK) SourceBuffer
--
--  Author : Peter Gavin, Andy Stewart
--  derived from sourceview bindings by Axel Simon and Duncan Coutts
--
--  Created: 18 December 2008
--
--  Copyright (C) 2003-2008 Peter Gavin, Duncan Coutts, Axel Simon
--  Copyright (C) 2010 Andy Stewart
--
--  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)
--
module Graphics.UI.Gtk.SourceView.SourceBuffer (
-- * Types
  SourceBuffer,
  SourceBufferClass,

-- * Methods
  castToSourceBuffer,
  sourceBufferNew,
  sourceBufferNewWithLanguage,
  sourceBufferSetHighlightSyntax,
  sourceBufferGetHighlightSyntax,
  sourceBufferSetLanguage,
  sourceBufferGetLanguage,
  sourceBufferSetHighlightMatchingBrackets,
  sourceBufferGetHighlightMatchingBrackets,
  sourceBufferSetStyleScheme,
  sourceBufferGetStyleScheme,
  sourceBufferSetMaxUndoLevels,
  sourceBufferGetMaxUndoLevels,
  sourceBufferGetCanUndo,
  sourceBufferGetCanRedo,
  sourceBufferUndo,
  sourceBufferRedo,
  sourceBufferBeginNotUndoableAction,
  sourceBufferEndNotUndoableAction,
  sourceBufferCreateSourceMark,
  sourceBufferGetSourceMarksAtLine,
  sourceBufferGetSourceMarksAtIter,
  sourceBufferRemoveSourceMarks,
  sourceBufferForwardIterToSourceMark,
  sourceBufferBackwardIterToSourceMark,
  sourceBufferEnsureHighlight,

-- * Attributes
  sourceBufferCanRedo,
  sourceBufferCanUndo,
  sourceBufferHighlightMatchingBrackets,
  sourceBufferHighlightSyntax,
  sourceBufferLanguage,
  sourceBufferSourceStyleScheme,
  sourceBufferMaxUndoLevels,

-- * Signals
  sourceBufferHighlightUpdated,
  sourceBufferRedoSignal,
  sourceBufferUndoSignal,
  sourceBufferSourceMarkUpdated,
  ) where

import Control.Monad	(liftM)
import Data.Maybe    (fromMaybe)

import System.Glib.FFI
import System.Glib.GList
import System.Glib.GObject              (constructNewGObject,
					 makeNewGObject)
{#import System.Glib.Properties#}
import System.Glib.Attributes
import Graphics.UI.Gtk.Abstract.Object	(makeNewObject)
{#import Graphics.UI.Gtk.SourceView.Types#}
{#import Graphics.UI.Gtk.SourceView.Signals#}
{#import Graphics.UI.Gtk.Multiline.TextIter#}

{#import Graphics.UI.Gtk.SourceView.SourceMark#}

{# context lib="gtk" prefix="gtk" #}

-- methods

-- | Create a new 'SourceBuffer', possibly
-- taking a 'TextTagTable'.
--
sourceBufferNew :: Maybe TextTagTable -> IO SourceBuffer
sourceBufferNew tt = constructNewGObject mkSourceBuffer $
  {#call unsafe source_buffer_new#}
  (fromMaybe (TextTagTable nullForeignPtr) tt)

-- | Create a new 'SourceBuffer'
-- with a 'SourceLanguage'.
--
sourceBufferNewWithLanguage :: SourceLanguage -> IO SourceBuffer
sourceBufferNewWithLanguage lang = constructNewGObject mkSourceBuffer $
  {#call unsafe source_buffer_new_with_language#} lang

-- | Controls whether syntax is highlighted in the buffer. If highlight is 'True', the text will be
-- highlighted according to the syntax patterns specified in the language set with
-- 'sourceBufferSetLanguage'. If highlight is 'False', syntax highlighting is disabled and all the
-- 'TextTag' objects that have been added by the syntax highlighting engine are removed from the
-- buffer.
sourceBufferSetHighlightSyntax :: SourceBuffer  -- ^ @buffer@    a 'SourceBuffer'.
                               -> Bool  -- ^ @highlight@ 'True' to enable syntax highlighting, 'False' to disable it.
                               -> IO ()
sourceBufferSetHighlightSyntax sb newVal =
  {#call unsafe source_buffer_set_highlight_syntax#} sb (fromBool newVal)

-- | Determines whether syntax highlighting is activated in the source buffer.
sourceBufferGetHighlightSyntax :: SourceBuffer
                               -> IO Bool  -- ^ returns 'True' if syntax highlighting is enabled, 'False' otherwise.
sourceBufferGetHighlightSyntax sb = liftM toBool $
  {#call unsafe source_buffer_get_highlight_syntax#} sb

-- | Associate a 'SourceLanguage' with the source buffer. If language is not-'Nothing' and syntax
-- highlighting is enabled (see 'sourceBufferSetHighlightSyntax', the syntax patterns defined
-- in language will be used to highlight the text contained in the buffer. If language is 'Nothing', the
-- text contained in the buffer is not highlighted.
sourceBufferSetLanguage :: SourceBuffer
                        -> Maybe SourceLanguage  -- ^ @language@ a 'SourceLanguage' to set, or 'Nothing'.
                        -> IO ()
sourceBufferSetLanguage sb lang =
  {#call unsafe source_buffer_set_language#}
    sb
    (fromMaybe (SourceLanguage nullForeignPtr) lang)

-- | Returns the 'SourceLanguage' associated with the buffer, see 'sourceBufferSetLanguage'.
sourceBufferGetLanguage :: SourceBuffer
                        -> IO (Maybe SourceLanguage) -- ^ returns 'SourceLanguage' associated with the buffer, or 'Nothing'.
sourceBufferGetLanguage sb =
  maybeNull (makeNewGObject mkSourceLanguage) $
  {#call unsafe source_buffer_get_language#} sb

-- | Controls the bracket match highlighting function in the buffer. If activated, when you position your
-- cursor over a bracket character (a parenthesis, a square bracket, etc.) the matching opening or
-- closing bracket character will be highlighted. You can specify the style with the
-- 'sourceBufferSetBracketMatchStyle' function.
sourceBufferSetHighlightMatchingBrackets :: SourceBuffer
                                         -> Bool  -- ^ @highlight@ 'True' if you want matching brackets highlighted.
                                         -> IO ()
sourceBufferSetHighlightMatchingBrackets sb newVal =
  {#call unsafe source_buffer_set_highlight_matching_brackets#} sb (fromBool newVal)

-- | Determines whether bracket match highlighting is activated for the source buffer.
sourceBufferGetHighlightMatchingBrackets :: SourceBuffer
                                         -> IO Bool  -- ^ returns 'True' if the source buffer will highlight matching brackets.
sourceBufferGetHighlightMatchingBrackets sb = liftM toBool $
  {#call unsafe source_buffer_get_highlight_matching_brackets#} sb

-- | Sets style scheme used by the buffer. If scheme is 'Nothing' no style scheme is used.
sourceBufferSetStyleScheme :: SourceBuffer
                           -> SourceStyleScheme  -- ^ @scheme@ style scheme.
                           -> IO ()
sourceBufferSetStyleScheme sb sss =
    {#call unsafe source_buffer_set_style_scheme#} sb sss

-- | Returns the 'SourceStyleScheme' currently used in buffer.
sourceBufferGetStyleScheme :: SourceBuffer
                           -> IO SourceStyleScheme -- ^ returns the 'SourceStyleScheme' set by 'sourceBufferSetStyleScheme', or 'Nothing'.
sourceBufferGetStyleScheme sb = makeNewGObject mkSourceStyleScheme $
  {#call unsafe source_buffer_get_style_scheme#} sb

-- | Sets the number of undo levels for user actions the buffer will track. If the number of user actions
-- exceeds the limit set by this function, older actions will be discarded.
--
-- If @maxUndoLevels@ is -1, no limit is set.
--
-- A new action is started whenever the function 'textBufferBeginUserAction' is called. In
-- general, this happens whenever the user presses any key which modifies the buffer, but the undo
-- manager will try to merge similar consecutive actions, such as multiple character insertions into
-- one action. But, inserting a newline does start a new action.
sourceBufferSetMaxUndoLevels :: SourceBuffer
                             -> Int  -- ^ @maxUndoLevels@ the desired maximum number of undo levels.
                             -> IO ()
sourceBufferSetMaxUndoLevels sb newVal =
  {#call unsafe source_buffer_set_max_undo_levels#} sb (fromIntegral newVal)

-- | Determines the number of undo levels the buffer will track for buffer edits.
sourceBufferGetMaxUndoLevels :: SourceBuffer
                             -> IO Int -- ^ returns the maximum number of possible undo levels or -1 if no limit is set.
sourceBufferGetMaxUndoLevels sb = liftM fromIntegral $
  {#call unsafe source_buffer_get_max_undo_levels#} sb

-- | Determines whether a source buffer can undo the last action.
sourceBufferGetCanUndo :: SourceBuffer
                       -> IO Bool -- ^ returns 'True' if it's possible to undo the last action.
sourceBufferGetCanUndo sb = liftM toBool $
  {#call unsafe source_buffer_can_undo#} sb

-- | Determines whether a source buffer can redo the last action (i.e. if the last operation was an
-- undo).
sourceBufferGetCanRedo :: SourceBuffer
                       -> IO Bool -- ^ returns 'True' if a redo is possible.
sourceBufferGetCanRedo sb = liftM toBool $
  {#call unsafe source_buffer_can_redo#} sb

-- | Undoes the last user action which modified the buffer. Use 'sourceBufferCanUndo' to check
-- whether a call to this function will have any effect.
--
-- Actions are defined as groups of operations between a call to 'textBufferBeginUserAction'
-- and 'textBufferEndUserAction' on the
-- same line.
sourceBufferUndo :: SourceBuffer -> IO ()
sourceBufferUndo sb =
  {#call source_buffer_undo#} sb

-- | Redoes the last undo operation. Use 'sourceBufferCanRedo' to check whether a call to this
-- function will have any effect.
sourceBufferRedo :: SourceBuffer -> IO ()
sourceBufferRedo sb =
  {#call source_buffer_redo#} sb

-- | Marks the beginning of a not undoable action on the buffer, disabling the undo manager. Typically
-- you would call this function before initially setting the contents of the buffer (e.g. when loading
-- a file in a text editor).
--
-- You may nest 'sourceBufferBeginNotUndoableAction' /
-- 'sourceBufferEndNotUndoableAction' blocks.
sourceBufferBeginNotUndoableAction :: SourceBuffer -> IO ()
sourceBufferBeginNotUndoableAction sb =
  {#call source_buffer_begin_not_undoable_action#} sb

-- | Marks the end of a not undoable action on the buffer. When the last not undoable block is closed
-- through the call to this function, the list of undo actions is cleared and the undo manager is
-- re-enabled.
sourceBufferEndNotUndoableAction :: SourceBuffer -> IO ()
sourceBufferEndNotUndoableAction sb =
  {#call source_buffer_end_not_undoable_action#} sb

-- | Creates a marker in the buffer of the given type.
--
-- *  A marker is
--    semantically very similar to a 'Graphics.UI.Gtk.Multiline.TextMark',
--    except it has a type
--    which is used by the 'SourceView' displaying the buffer to show a
--    pixmap on the left margin, at the line the marker is in.  Because
--    of this, a marker is generally associated to a line and not a
--    character position.  Markers are also accessible through a position
--    or range in the buffer.
--
-- *  Markers are implemented using 'Graphics.UI.Gtk.Multiline.TextMark',
--    so all characteristics
--    and restrictions to marks apply to markers too.  These includes
--    life cycle issues and 'Graphics.UI.Gtk.Multiline.TextMark.onMarkSet'
--    and 'Graphics.UI.Gtk.Multiline.TextMark.onMarkDeleted' signal
--    emissions.
--
-- *  Like a 'Graphics.UI.Gtk.Multiline.TextMark', a 'SourceMarker'
--    can be anonymous if the
--    passed name is @Nothing@.  Also, the buffer owns the markers so you
--    shouldn't unreference it.

sourceBufferCreateSourceMark :: SourceBuffer -- the buffer
                         -> Maybe String -- the name of the mark
                         -> String -- the category of the mark
                         -> TextIter -> IO SourceMark
sourceBufferCreateSourceMark sb name category iter =
  makeNewGObject mkSourceMark $
  maybeWith withCString name       $ \strPtr1 ->
  withCString category $ \strPtr2 ->
  {#call source_buffer_create_source_mark#} sb strPtr1 strPtr2 iter

-- | Returns the list of marks of the given category at line. If category is empty, all marks at line are
-- returned.
sourceBufferGetSourceMarksAtLine :: SourceBuffer  -- ^ @buffer@   a 'SourceBuffer'.
                                 -> Int -- ^ @line@     a line number.
                                 -> String -- ^ @category@ category to search for or empty
                                 -> IO [SourceMark]
sourceBufferGetSourceMarksAtLine buffer line category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_get_source_marks_at_line #}
    buffer
    (fromIntegral line)
    categoryPtr
  >>= readGSList
  >>= mapM (\markPtr -> makeNewGObject mkSourceMark (return markPtr))

-- | Returns the list of marks of the given category at iter. If category is empty it returns all marks at
-- iter.
sourceBufferGetSourceMarksAtIter :: SourceBuffer -- ^ @buffer@   a 'SourceBuffer'.
                                 -> TextIter -- ^ @iter@     an iterator.
                                 -> String -- ^ @category@ category to search for or empty
                                 -> IO [SourceMark]
sourceBufferGetSourceMarksAtIter buffer iter category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_get_source_marks_at_iter #}
    buffer
    iter
    categoryPtr
  >>= readGSList
  >>= mapM (\markPtr -> makeNewGObject mkSourceMark (return markPtr))

-- | Remove all marks of category between start and end from the buffer. If category is empty, all marks
-- in the range will be removed.
sourceBufferRemoveSourceMarks :: SourceBuffer -- ^ @buffer@   a 'SourceBuffer'.
                              -> TextIter -- ^ @start@    a 'TextIter'
                              -> TextIter -- ^ @end@      a 'TextIter'
                              -> String -- ^ @category@ category to search for or empty
                              -> IO ()
sourceBufferRemoveSourceMarks buffer start end category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_remove_source_marks #}
     buffer
     start
     end
     categoryPtr

-- | Moves iter to the position of the next 'SourceMark' of the given category. Returns 'True' if iter was
-- moved. If category is empty, the next source mark can be of any category.
sourceBufferForwardIterToSourceMark :: SourceBuffer -- ^ @buffer@   a 'SourceBuffer'.
                                    -> TextIter -- ^ @iter@     an iterator.
                                    -> String -- ^ @category@ category to search for or emtpy
                                    -> IO Bool -- ^ returns  whether iter moved.
sourceBufferForwardIterToSourceMark buffer iter category =
  liftM toBool $
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_forward_iter_to_source_mark #}
    buffer
    iter
    categoryPtr

-- | Moves iter to the position of the previous 'SourceMark' of the given category. Returns 'True' if iter
-- was moved. If category is empty, the previous source mark can be of any category.
sourceBufferBackwardIterToSourceMark :: SourceBuffer  -- ^ @buffer@   a 'SourceBuffer'.
                                     -> TextIter -- ^ @iter@     an iterator.
                                     -> String -- ^ @category@ category to search for or emtpy
                                     -> IO Bool -- ^ returns  whether iter moved.
sourceBufferBackwardIterToSourceMark buffer iter category =
  liftM toBool $
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_backward_iter_to_source_mark #}
    buffer
    iter
    categoryPtr

-- | Forces buffer to analyze and highlight the given area synchronously.
--
-- Note
--
-- This is a potentially slow operation and should be used only when you need to make sure that some
-- text not currently visible is highlighted, for instance before printing.
sourceBufferEnsureHighlight :: SourceBuffer
                            -> TextIter  -- ^ @start@  start of the area to highlight.
                            -> TextIter  -- ^ @end@    end of the area to highlight.
                            -> IO ()
sourceBufferEnsureHighlight sb start end =
    {#call source_buffer_ensure_highlight#} sb start end

-- | Whether Redo operation is possible.
--
-- Default value: 'False'
--
sourceBufferCanRedo :: ReadAttr SourceBuffer Bool
sourceBufferCanRedo = readAttrFromBoolProperty "can-redo"

-- | Whether Undo operation is possible.
--
-- Default value: 'False'
sourceBufferCanUndo :: ReadAttr SourceBuffer Bool
sourceBufferCanUndo = readAttrFromBoolProperty "can-undo"

-- | Whether to highlight matching brackets in the buffer.
--
-- Default value: 'True'
--
sourceBufferHighlightMatchingBrackets :: Attr SourceBuffer Bool
sourceBufferHighlightMatchingBrackets = newAttrFromBoolProperty "highlight-matching-brackets"

-- | Whether to highlight syntax in the buffer.
--
-- Default value: 'True'
--
sourceBufferHighlightSyntax :: Attr SourceBuffer Bool
sourceBufferHighlightSyntax = newAttrFromBoolProperty "highlight-matching-brackets"

-- | Language object to get highlighting patterns from.
--
sourceBufferLanguage :: Attr SourceBuffer (Maybe SourceLanguage)
sourceBufferLanguage = newAttrFromMaybeObjectProperty "language" gTypeSourceLanguage

-- | Number of undo levels for the buffer. -1 means no limit. This property will only affect the default
-- undo manager.
--
-- Allowed values: >= GMaxulong
--
-- Default value: 1000
--
sourceBufferMaxUndoLevels :: Attr SourceBuffer Int
sourceBufferMaxUndoLevels = newAttrFromIntProperty "max-undo-levels"

-- | Style scheme. It contains styles for syntax highlighting, optionally foreground, background, cursor
-- color, current line color, and matching brackets style.
--
sourceBufferSourceStyleScheme :: Attr SourceBuffer (Maybe SourceStyleScheme)
sourceBufferSourceStyleScheme = newAttrFromMaybeObjectProperty "style-scheme" gTypeSourceStyleScheme

-- |
--
sourceBufferHighlightUpdated :: Signal SourceBuffer (TextIter -> TextIter -> IO ())
sourceBufferHighlightUpdated = Signal $ connect_BOXED_BOXED__NONE "highlight-updated" mkTextIterCopy mkTextIterCopy

-- |
--
sourceBufferRedoSignal :: Signal SourceBuffer (IO ())
sourceBufferRedoSignal = Signal $ connect_NONE__NONE "redo"

-- |
--
sourceBufferUndoSignal :: Signal SourceBuffer (IO ())
sourceBufferUndoSignal = Signal $ connect_NONE__NONE "undo"

-- | The 'sourceBufferMarkUpdated' signal is emitted each time a mark is added to, moved or removed from the
-- buffer.
--
sourceBufferSourceMarkUpdated :: Signal SourceBuffer (TextMark -> IO ())
sourceBufferSourceMarkUpdated = Signal $ connect_OBJECT__NONE "source-mark-updated"

{-# LANGUAGE CPP #-}
-- -*-haskell-*-
--  GIMP Toolkit (GTK) SourceBuffer
--
--  Author : Peter Gavin, Andy Stewart
--  derived from sourceview bindings by Axel Simon and Duncan Coutts
--
--  Created: 18 December 2008
--
--  Copyright (C) 2003-2008 Peter Gavin, Duncan Coutts, Axel Simon
--  Copyright (C) 2010 Andy Stewart
--
--  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)
--
module Graphics.UI.Gtk.SourceView.SourceBuffer (
-- * Types
  SourceBuffer,
  SourceBufferClass,

-- * Methods
  castToSourceBuffer,
  sourceBufferNew,
  sourceBufferNewWithLanguage,
  sourceBufferSetHighlightSyntax,
  sourceBufferGetHighlightSyntax,
  sourceBufferSetLanguage,
  sourceBufferGetLanguage,
  sourceBufferSetHighlightMatchingBrackets,
  sourceBufferGetHighlightMatchingBrackets,
  sourceBufferSetStyleScheme,
  sourceBufferGetStyleScheme,
  sourceBufferSetMaxUndoLevels,
  sourceBufferGetMaxUndoLevels,
  sourceBufferGetCanUndo,
  sourceBufferGetCanRedo,
  sourceBufferUndo,
  sourceBufferRedo,
  sourceBufferBeginNotUndoableAction,
  sourceBufferEndNotUndoableAction,
  sourceBufferCreateSourceMark,
  sourceBufferGetSourceMarksAtLine,
  sourceBufferGetSourceMarksAtIter,
  sourceBufferRemoveSourceMarks,
  sourceBufferForwardIterToSourceMark,
  sourceBufferBackwardIterToSourceMark,
  sourceBufferEnsureHighlight,

-- * Attributes
  sourceBufferCanRedo,
  sourceBufferCanUndo,
  sourceBufferHighlightMatchingBrackets,
  sourceBufferHighlightSyntax,
  sourceBufferLanguage,
  sourceBufferSourceStyleScheme,
  sourceBufferMaxUndoLevels,

-- * Signals
  sourceBufferHighlightUpdated,
  sourceBufferRedoSignal,
  sourceBufferUndoSignal,
  sourceBufferSourceMarkUpdated,
  ) where

import Control.Monad	(liftM)
import Data.Maybe    (fromMaybe)

import System.Glib.FFI
import System.Glib.GList
import System.Glib.GObject              (constructNewGObject,
					 makeNewGObject)
{#import System.Glib.Properties#}
import System.Glib.Attributes
import Graphics.UI.Gtk.Abstract.Object	(makeNewObject)
{#import Graphics.UI.Gtk.SourceView.Types#}
{#import Graphics.UI.Gtk.SourceView.Signals#}
{#import Graphics.UI.Gtk.Multiline.TextIter#}

{#import Graphics.UI.Gtk.SourceView.SourceMark#}

{# context lib="gtk" prefix="gtk" #}

-- methods

-- | Create a new 'SourceBuffer', possibly
-- taking a 'TextTagTable'.
--
sourceBufferNew :: Maybe TextTagTable -> IO SourceBuffer
sourceBufferNew tt = constructNewGObject mkSourceBuffer $
  {#call unsafe source_buffer_new#}
  (fromMaybe (TextTagTable nullForeignPtr) tt)

-- | Create a new 'SourceBuffer'
-- with a 'SourceLanguage'.
--
sourceBufferNewWithLanguage :: SourceLanguage -> IO SourceBuffer
sourceBufferNewWithLanguage lang = constructNewGObject mkSourceBuffer $
  {#call unsafe source_buffer_new_with_language#} lang

-- | Controls whether syntax is highlighted in the buffer. If highlight is 'True', the text will be
-- highlighted according to the syntax patterns specified in the language set with
-- 'sourceBufferSetLanguage'. If highlight is 'False', syntax highlighting is disabled and all the
-- 'TextTag' objects that have been added by the syntax highlighting engine are removed from the
-- buffer.
sourceBufferSetHighlightSyntax :: SourceBuffer  -- ^ @buffer@    a 'SourceBuffer'.
                               -> Bool  -- ^ @highlight@ 'True' to enable syntax highlighting, 'False' to disable it.
                               -> IO ()
sourceBufferSetHighlightSyntax sb newVal =
  {#call unsafe source_buffer_set_highlight_syntax#} sb (fromBool newVal)

-- | Determines whether syntax highlighting is activated in the source buffer.
sourceBufferGetHighlightSyntax :: SourceBuffer
                               -> IO Bool  -- ^ returns 'True' if syntax highlighting is enabled, 'False' otherwise.
sourceBufferGetHighlightSyntax sb = liftM toBool $
  {#call unsafe source_buffer_get_highlight_syntax#} sb

-- | Associate a 'SourceLanguage' with the source buffer. If language is not-'Nothing' and syntax
-- highlighting is enabled (see 'sourceBufferSetHighlightSyntax', the syntax patterns defined
-- in language will be used to highlight the text contained in the buffer. If language is 'Nothing', the
-- text contained in the buffer is not highlighted.
sourceBufferSetLanguage :: SourceBuffer
                        -> SourceLanguage  -- ^ @language@ a 'SourceLanguage' to set, or 'Nothing'.
                        -> IO ()
sourceBufferSetLanguage sb lang =
  {#call unsafe source_buffer_set_language#} sb lang

-- | Returns the 'SourceLanguage' associated with the buffer, see 'sourceBufferSetLanguage'. The
-- returned object should not be unreferenced by the user.
sourceBufferGetLanguage :: SourceBuffer
                        -> IO SourceLanguage -- ^ returns 'SourceLanguage' associated with the buffer, or 'Nothing'.
sourceBufferGetLanguage sb = makeNewGObject mkSourceLanguage $
  {#call unsafe source_buffer_get_language#} sb

-- | Controls the bracket match highlighting function in the buffer. If activated, when you position your
-- cursor over a bracket character (a parenthesis, a square bracket, etc.) the matching opening or
-- closing bracket character will be highlighted. You can specify the style with the
-- 'sourceBufferSetBracketMatchStyle' function.
sourceBufferSetHighlightMatchingBrackets :: SourceBuffer
                                         -> Bool  -- ^ @highlight@ 'True' if you want matching brackets highlighted.
                                         -> IO ()
sourceBufferSetHighlightMatchingBrackets sb newVal =
  {#call unsafe source_buffer_set_highlight_matching_brackets#} sb (fromBool newVal)

-- | Determines whether bracket match highlighting is activated for the source buffer.
sourceBufferGetHighlightMatchingBrackets :: SourceBuffer
                                         -> IO Bool  -- ^ returns 'True' if the source buffer will highlight matching brackets.
sourceBufferGetHighlightMatchingBrackets sb = liftM toBool $
  {#call unsafe source_buffer_get_highlight_matching_brackets#} sb

-- | Sets style scheme used by the buffer. If scheme is 'Nothing' no style scheme is used.
sourceBufferSetStyleScheme :: SourceBuffer
                           -> SourceStyleScheme  -- ^ @scheme@ style scheme.
                           -> IO ()
sourceBufferSetStyleScheme sb sss =
    {#call unsafe source_buffer_set_style_scheme#} sb sss

-- | Returns the 'SourceStyleScheme' currently used in buffer.
sourceBufferGetStyleScheme :: SourceBuffer
                           -> IO SourceStyleScheme -- ^ returns the 'SourceStyleScheme' set by 'sourceBufferSetStyleScheme', or 'Nothing'.
sourceBufferGetStyleScheme sb = makeNewGObject mkSourceStyleScheme $
  {#call unsafe source_buffer_get_style_scheme#} sb

-- | Sets the number of undo levels for user actions the buffer will track. If the number of user actions
-- exceeds the limit set by this function, older actions will be discarded.
--
-- If @maxUndoLevels@ is -1, no limit is set.
--
-- A new action is started whenever the function 'textBufferBeginUserAction' is called. In
-- general, this happens whenever the user presses any key which modifies the buffer, but the undo
-- manager will try to merge similar consecutive actions, such as multiple character insertions into
-- one action. But, inserting a newline does start a new action.
sourceBufferSetMaxUndoLevels :: SourceBuffer
                             -> Int  -- ^ @maxUndoLevels@ the desired maximum number of undo levels.
                             -> IO ()
sourceBufferSetMaxUndoLevels sb newVal =
  {#call unsafe source_buffer_set_max_undo_levels#} sb (fromIntegral newVal)

-- | Determines the number of undo levels the buffer will track for buffer edits.
sourceBufferGetMaxUndoLevels :: SourceBuffer
                             -> IO Int -- ^ returns the maximum number of possible undo levels or -1 if no limit is set.
sourceBufferGetMaxUndoLevels sb = liftM fromIntegral $
  {#call unsafe source_buffer_get_max_undo_levels#} sb

-- | Determines whether a source buffer can undo the last action.
sourceBufferGetCanUndo :: SourceBuffer
                       -> IO Bool -- ^ returns 'True' if it's possible to undo the last action.
sourceBufferGetCanUndo sb = liftM toBool $
  {#call unsafe source_buffer_can_undo#} sb

-- | Determines whether a source buffer can redo the last action (i.e. if the last operation was an
-- undo).
sourceBufferGetCanRedo :: SourceBuffer
                       -> IO Bool -- ^ returns 'True' if a redo is possible.
sourceBufferGetCanRedo sb = liftM toBool $
  {#call unsafe source_buffer_can_redo#} sb

-- | Undoes the last user action which modified the buffer. Use 'sourceBufferCanUndo' to check
-- whether a call to this function will have any effect.
--
-- Actions are defined as groups of operations between a call to 'textBufferBeginUserAction'
-- and 'textBufferEndUserAction' on the
-- same line.
sourceBufferUndo :: SourceBuffer -> IO ()
sourceBufferUndo sb =
  {#call source_buffer_undo#} sb

-- | Redoes the last undo operation. Use 'sourceBufferCanRedo' to check whether a call to this
-- function will have any effect.
sourceBufferRedo :: SourceBuffer -> IO ()
sourceBufferRedo sb =
  {#call source_buffer_redo#} sb

-- | Marks the beginning of a not undoable action on the buffer, disabling the undo manager. Typically
-- you would call this function before initially setting the contents of the buffer (e.g. when loading
-- a file in a text editor).
--
-- You may nest 'sourceBufferBeginNotUndoableAction' /
-- 'sourceBufferEndNotUndoableAction' blocks.
sourceBufferBeginNotUndoableAction :: SourceBuffer -> IO ()
sourceBufferBeginNotUndoableAction sb =
  {#call source_buffer_begin_not_undoable_action#} sb

-- | Marks the end of a not undoable action on the buffer. When the last not undoable block is closed
-- through the call to this function, the list of undo actions is cleared and the undo manager is
-- re-enabled.
sourceBufferEndNotUndoableAction :: SourceBuffer -> IO ()
sourceBufferEndNotUndoableAction sb =
  {#call source_buffer_end_not_undoable_action#} sb

-- | Creates a marker in the buffer of the given type.
--
-- *  A marker is
--    semantically very similar to a 'Graphics.UI.Gtk.Multiline.TextMark',
--    except it has a type
--    which is used by the 'SourceView' displaying the buffer to show a
--    pixmap on the left margin, at the line the marker is in.  Because
--    of this, a marker is generally associated to a line and not a
--    character position.  Markers are also accessible through a position
--    or range in the buffer.
--
-- *  Markers are implemented using 'Graphics.UI.Gtk.Multiline.TextMark',
--    so all characteristics
--    and restrictions to marks apply to markers too.  These includes
--    life cycle issues and 'Graphics.UI.Gtk.Multiline.TextMark.onMarkSet'
--    and 'Graphics.UI.Gtk.Multiline.TextMark.onMarkDeleted' signal
--    emissions.
--
-- *  Like a 'Graphics.UI.Gtk.Multiline.TextMark', a 'SourceMarker'
--    can be anonymous if the
--    passed name is @Nothing@.  Also, the buffer owns the markers so you
--    shouldn't unreference it.

sourceBufferCreateSourceMark :: SourceBuffer -- the buffer
                         -> Maybe String -- the name of the mark
                         -> String -- the category of the mark
                         -> TextIter -> IO SourceMark
sourceBufferCreateSourceMark sb name category iter =
  makeNewGObject mkSourceMark $
  maybeWith withCString name       $ \strPtr1 ->
  withCString category $ \strPtr2 ->
  {#call source_buffer_create_source_mark#} sb strPtr1 strPtr2 iter

-- | Returns the list of marks of the given category at line. If category is empty, all marks at line are
-- returned.
sourceBufferGetSourceMarksAtLine :: SourceBuffer  -- ^ @buffer@   a 'SourceBuffer'.
                                 -> Int -- ^ @line@     a line number.
                                 -> String -- ^ @category@ category to search for or empty
                                 -> IO [SourceMark]
sourceBufferGetSourceMarksAtLine buffer line category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_get_source_marks_at_line #}
    buffer
    (fromIntegral line)
    categoryPtr
  >>= readGSList
  >>= mapM (\markPtr -> makeNewGObject mkSourceMark (return markPtr))

-- | Returns the list of marks of the given category at iter. If category is empty it returns all marks at
-- iter.
sourceBufferGetSourceMarksAtIter :: SourceBuffer -- ^ @buffer@   a 'SourceBuffer'.
                                 -> TextIter -- ^ @iter@     an iterator.
                                 -> String -- ^ @category@ category to search for or empty
                                 -> IO [SourceMark]
sourceBufferGetSourceMarksAtIter buffer iter category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_get_source_marks_at_iter #}
    buffer
    iter
    categoryPtr
  >>= readGSList
  >>= mapM (\markPtr -> makeNewGObject mkSourceMark (return markPtr))

-- | Remove all marks of category between start and end from the buffer. If category is empty, all marks
-- in the range will be removed.
sourceBufferRemoveSourceMarks :: SourceBuffer -- ^ @buffer@   a 'SourceBuffer'.
                              -> TextIter -- ^ @start@    a 'TextIter'
                              -> TextIter -- ^ @end@      a 'TextIter'
                              -> String -- ^ @category@ category to search for or empty
                              -> IO ()
sourceBufferRemoveSourceMarks buffer start end category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_remove_source_marks #}
     buffer
     start
     end
     categoryPtr

-- | Moves iter to the position of the next 'SourceMark' of the given category. Returns 'True' if iter was
-- moved. If category is empty, the next source mark can be of any category.
sourceBufferForwardIterToSourceMark :: SourceBuffer -- ^ @buffer@   a 'SourceBuffer'.
                                    -> TextIter -- ^ @iter@     an iterator.
                                    -> String -- ^ @category@ category to search for or emtpy
                                    -> IO Bool -- ^ returns  whether iter moved.
sourceBufferForwardIterToSourceMark buffer iter category =
  liftM toBool $
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_forward_iter_to_source_mark #}
    buffer
    iter
    categoryPtr

-- | Moves iter to the position of the previous 'SourceMark' of the given category. Returns 'True' if iter
-- was moved. If category is empty, the previous source mark can be of any category.
sourceBufferBackwardIterToSourceMark :: SourceBuffer  -- ^ @buffer@   a 'SourceBuffer'.
                                     -> TextIter -- ^ @iter@     an iterator.
                                     -> String -- ^ @category@ category to search for or emtpy
                                     -> IO Bool -- ^ returns  whether iter moved.
sourceBufferBackwardIterToSourceMark buffer iter category =
  liftM toBool $
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_backward_iter_to_source_mark #}
    buffer
    iter
    categoryPtr

-- | Forces buffer to analyze and highlight the given area synchronously.
--
-- Note
--
-- This is a potentially slow operation and should be used only when you need to make sure that some
-- text not currently visible is highlighted, for instance before printing.
sourceBufferEnsureHighlight :: SourceBuffer
                            -> TextIter  -- ^ @start@  start of the area to highlight.
                            -> TextIter  -- ^ @end@    end of the area to highlight.
                            -> IO ()
sourceBufferEnsureHighlight sb start end =
    {#call source_buffer_ensure_highlight#} sb start end

-- | Whether Redo operation is possible.
--
-- Default value: 'False'
--
sourceBufferCanRedo :: ReadAttr SourceBuffer Bool
sourceBufferCanRedo = readAttrFromBoolProperty "can-redo"

-- | Whether Undo operation is possible.
--
-- Default value: 'False'
sourceBufferCanUndo :: ReadAttr SourceBuffer Bool
sourceBufferCanUndo = readAttrFromBoolProperty "can-undo"

-- | Whether to highlight matching brackets in the buffer.
--
-- Default value: 'True'
--
sourceBufferHighlightMatchingBrackets :: Attr SourceBuffer Bool
sourceBufferHighlightMatchingBrackets = newAttrFromBoolProperty "highlight-matching-brackets"

-- | Whether to highlight syntax in the buffer.
--
-- Default value: 'True'
--
sourceBufferHighlightSyntax :: Attr SourceBuffer Bool
sourceBufferHighlightSyntax = newAttrFromBoolProperty "highlight-matching-brackets"

-- | Language object to get highlighting patterns from.
--
sourceBufferLanguage :: Attr SourceBuffer (Maybe SourceLanguage)
sourceBufferLanguage = newAttrFromMaybeObjectProperty "language" gTypeSourceLanguage

-- | Number of undo levels for the buffer. -1 means no limit. This property will only affect the default
-- undo manager.
--
-- Allowed values: >= GMaxulong
--
-- Default value: 1000
--
sourceBufferMaxUndoLevels :: Attr SourceBuffer Int
sourceBufferMaxUndoLevels = newAttrFromIntProperty "max-undo-levels"

-- | Style scheme. It contains styles for syntax highlighting, optionally foreground, background, cursor
-- color, current line color, and matching brackets style.
--
sourceBufferSourceStyleScheme :: Attr SourceBuffer (Maybe SourceStyleScheme)
sourceBufferSourceStyleScheme = newAttrFromMaybeObjectProperty "style-scheme" gTypeSourceStyleScheme

-- |
--
sourceBufferHighlightUpdated :: Signal SourceBuffer (TextIter -> TextIter -> IO ())
sourceBufferHighlightUpdated = Signal $ connect_BOXED_BOXED__NONE "highlight-updated" mkTextIterCopy mkTextIterCopy

-- |
--
sourceBufferRedoSignal :: Signal SourceBuffer (IO ())
sourceBufferRedoSignal = Signal $ connect_NONE__NONE "redo"

-- |
--
sourceBufferUndoSignal :: Signal SourceBuffer (IO ())
sourceBufferUndoSignal = Signal $ connect_NONE__NONE "undo"

-- | The 'sourceBufferMarkUpdated' signal is emitted each time a mark is added to, moved or removed from the
-- buffer.
--
sourceBufferSourceMarkUpdated :: Signal SourceBuffer (TextMark -> IO ())
sourceBufferSourceMarkUpdated = Signal $ connect_OBJECT__NONE "source-mark-updated"