{-# LANGUAGE ForeignFunctionInterface #-}

{-# LINE 2 "./System/XFCE/Xfconf/Binding.chs" #-}
-- -*-haskell-*-
--

{- | Xfconf-GObject Binding -- Functions to bind Xfconf properties to
   GObject properties.

   Note that this haskell API follows closely the original C API. Object
   properties should be given using their string name from the C API
   and not their Haskell name deriving from
   'System.Glib.Attributes.ReadWriteAttr'.

   For more information, see:
   http:\/\/docs.xfce.org\/api\/xfconf\/xfconf-xfconf-binding.html
-}






{-# LINE 22 "./System/XFCE/Xfconf/Binding.chs" #-}

module System.XFCE.Xfconf.Binding (
                -- * Detail
                -- $details

                -- * Example
                -- $example

                -- * Types
                XfconfBindingID,

                -- * Functions
                xfconfBind,
                xfconfBindGdkColor,
                xfconfUnbind,
                xfconfUnbindAll,
                xfconfUnbindByProperty,

                -- re-exports glib gtype constants
                module System.Glib.GTypeConstants

                ) where

import System.Glib.GObject (GObject(GObject), GObjectClass(toGObject))
import System.Glib.GType (GType)
import System.Glib.GTypeConstants
import System.Glib.UTFString

import System.XFCE.Xfconf.FFI
import System.XFCE.Xfconf.Types
{-# LINE 52 "./System/XFCE/Xfconf/Binding.chs" #-}

{----------------------------------------------------------------------
-- Details
----------------------------------------------------------------------}

-- $details
-- Often it may be useful to bind an Xfconf property to a GObject
-- property. Settings dialogs often display the current value of an
-- Xfconf property, and a user may edit the value to change the value in
-- the Xfconf store. If the Xfconf property changes outside the settings
-- dialog, the user will usually want to see the settings dialog
-- automatically update to reflect the new value. With a single line
-- of code, Xfconf's binding functionality can automate all this.

{----------------------------------------------------------------------
-- Example (from Tests/Demo.hs)
----------------------------------------------------------------------}

-- $example
-- From the demo program in @\"Tests/Demo.hs\"@
--
-- @
-- chan \<- channelGet \"Demo\"
-- --
-- check0 \<- checkButtonNewWithLabel \"Check me \!\"
-- label0 \<- labelNew (Just \"\<null>\")
-- check1 \<- checkButtonNewWithLabel \"Check me !\"
-- --
-- let xfconf_property = \"\/check\"
-- \ \ \ \ obj_property = \"active\"    -- toggleButtonActive attribute
-- --
-- -- Signals voodoo \\o\/
-- -- * bind check buttons from\/to xfconfd
-- -- * thus, their \"active\" state will remain synchronized
-- xfsig0 \<- xfconfBind chan xfconf_property bool check0 obj_property
-- xfsig1 \<- xfconfBind chan xfconf_property bool check1 obj_property
-- --
-- -- * monitor xfconfd and update the label accordingly
-- onPropertyChanged chan $ \\key maybeValue -> do
-- \ \ if key \/= xfconf_property
-- \ \ \ then return ()
-- \ \ \ else case maybeValue of
-- \ \ \ \ \ Just (XfconfBool True) -> labelSetText label0 \"checked !\"
-- \ \ \ \ \ Just (XfconfBool False) -> labelSetText label0 \"unchecked !\"
-- \ \ \ \ \ _ -> labelSetText label0 \"UNKNOWN\"
-- --
-- -- Who cares about memory management nowadays ?
-- onDestroy window $ do
-- \ \ \ \ \ \ \ \ mainQuit
-- \ \ \ \ \ \ \ \ putStrLn \"ByeBye\"
-- @

{----------------------------------------------------------------------
-- Types and marshallers
----------------------------------------------------------------------}

-- | ID number that can be used to later remove corresponding bindings.
newtype XfconfBindingID = XfconfBindingID {unXfconfBindingID :: CULong}

-- | convenient marshall in function
withGObject :: GObjectClass obj => obj -> (Ptr () -> IO b) -> IO b
withGObject obj = let (GObject ptr) = toGObject obj
                  in withForeignPtr (castForeignPtr ptr)

{----------------------------------------------------------------------
-- Bindings
----------------------------------------------------------------------}

-- | Binds an Xfconf property to a GObject property. If the property is
-- changed via either the GObject or Xfconf, the corresponding property
-- will also be updated.
--
-- Note that @xfconf property type@ is required since @xfconf property@
-- may or may not already exist in the Xfconf store. The type of @object
-- property@ will be determined automatically. If the two types do not
-- match, a conversion will be attempted.
xfconfBind :: (XfconfChannelClass conf, GObjectClass obj)
           => conf -- ^ channel
           -> String -- ^ xfconf property
           -> GType -- ^ xfconf property type
           -> obj -- ^ object
           -> String -- ^ object property
           -> IO XfconfBindingID -- ^ Xfconf binding ID
xfconfBind chan0 prop1 type2 obj3 prop4 =
    withUTFString prop1 $ \prop1' ->
    withGObject obj3 $ \obj3' ->
    withUTFString prop4 $ \prop4' ->
    let chan0' = toXfconfChannel chan0
        f = (\(XfconfChannel arg1) arg2 arg3 arg4 arg5 -> withForeignPtr arg1 $ \argPtr1 ->xfconf_g_property_bind argPtr1 arg2 arg3 arg4 arg5)
{-# LINE 141 "./System/XFCE/Xfconf/Binding.chs" #-}
    in XfconfBindingID `fmap` f chan0' prop1' type2 obj3' prop4'

-- | Binds an Xfconf property to a GObject property of type
-- GDK_TYPE_COLOR (aka a GdkColor struct or simply 'Color' in Haskell
-- Pango library). If the property is changed via either the GObject or
-- Xfconf, the corresponding property will also be updated.
--
-- This is a special-case binding; the GdkColor struct is not ideal
-- as-is for binding to a property, so it is stored in the Xfconf store
-- as four 16-bit unsigned ints (red, green, blue, alpha). Since
-- GdkColor (currently) only supports RGB and not RGBA, the last value
-- will always be set to 0xFFFF.
xfconfBindGdkColor :: (XfconfChannelClass conf, GObjectClass obj)
                   => conf -- ^ channel
                   -> String -- ^ xfconf property
                   -> obj -- ^ object
                   -> String -- ^ object property
                   -> IO XfconfBindingID
xfconfBindGdkColor chan0 prop1 obj2 prop3 =
    withUTFString prop1 $ \prop1' ->
    withGObject obj2 $ \obj2' ->
    withUTFString prop3 $ \prop3' ->
    let chan0' = toXfconfChannel chan0
        f = (\(XfconfChannel arg1) arg2 arg3 arg4 -> withForeignPtr arg1 $ \argPtr1 ->xfconf_g_property_bind_gdkcolor argPtr1 arg2 arg3 arg4)
{-# LINE 165 "./System/XFCE/Xfconf/Binding.chs" #-}
    in XfconfBindingID `fmap` f chan0' prop1' obj2' prop3'

-- | Removes an Xfconf/GObject property binding based on the binding
-- 'XfconfBindingID' number. See 'xfconfBind'.
xfconfUnbind :: XfconfBindingID -> IO ()
xfconfUnbind = xfconf_g_property_unbind . unXfconfBindingID

-- | Causes an Xfconf channel previously bound to a GObject property
-- (see 'xfconfBind') to no longer be bound.
xfconfUnbindByProperty :: (XfconfChannelClass conf, GObjectClass obj)
                       => conf -- ^ channel
                       -> String -- ^ channel property
                       -> obj -- ^ object
                       -> String -- ^ object property
                       -> IO ()
xfconfUnbindByProperty conf0 prop1 obj2 prop3 =
        withUTFString prop1 $ \prop1' ->
        withGObject obj2 $ \obj2' ->
        withUTFString prop3 $ \prop3' ->
        let conf0' = toXfconfChannel conf0
            f = (\(XfconfChannel arg1) arg2 arg3 arg4 -> withForeignPtr arg1 $ \argPtr1 ->xfconf_g_property_unbind_by_property argPtr1 arg2 arg3 arg4)
{-# LINE 186 "./System/XFCE/Xfconf/Binding.chs" #-}
        in f conf0' prop1' obj2' prop3'

-- | Unbinds all Xfconf channel bindings (see 'xfconfBind')
-- to object. If object is an 'XfconfChannel', it will unbind all xfconf
-- properties on that channel. If object is a regular 'GObject' with
-- properties bound to a channel, all those bindings will be removed.
xfconfUnbindAll :: GObjectClass obj => obj -> IO ()
xfconfUnbindAll entity = withGObject entity unbind
  where unbind ptr = xfconf_g_property_unbind_all (castPtr ptr)

{----------------------------------------------------------------------
-- TODO

- xfconf-binding.h function list
-
- > bash $ sed '/^\(\/\| \*\|#\)/d' xfconf-binding.h | grep '('
-

DEMO xfconf_g_property_bind
DONE xfconf_g_property_bind_gdkcolor
DEMO xfconf_g_property_unbind
DEMO xfconf_g_property_unbind_all
DEMO xfconf_g_property_unbind_by_property

----------------------------------------------------------------------}

-- vim:filetype=haskell:

foreign import ccall unsafe "xfconf_g_property_bind"
  xfconf_g_property_bind :: ((Ptr XfconfChannel) -> ((Ptr CChar) -> (CULong -> ((Ptr ()) -> ((Ptr CChar) -> (IO CULong))))))

foreign import ccall unsafe "xfconf_g_property_bind_gdkcolor"
  xfconf_g_property_bind_gdkcolor :: ((Ptr XfconfChannel) -> ((Ptr CChar) -> ((Ptr ()) -> ((Ptr CChar) -> (IO CULong)))))

foreign import ccall unsafe "xfconf_g_property_unbind"
  xfconf_g_property_unbind :: (CULong -> (IO ()))

foreign import ccall unsafe "xfconf_g_property_unbind_by_property"
  xfconf_g_property_unbind_by_property :: ((Ptr XfconfChannel) -> ((Ptr CChar) -> ((Ptr ()) -> ((Ptr CChar) -> (IO ())))))

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