glib-0.12.4: System/Glib/Signals.chs
{-# LANGUAGE CPP #-}
{-# CFILES hsgclosure.c #-}
-- -*-haskell-*-
-- Callback installers for the GIMP Toolkit (GTK) Binding for Haskell
--
-- Author : Axel Simon
--
-- Created: 1 July 2000
--
-- Copyright (C) 2000-2005 Axel Simon, Duncan Coutts
--
-- 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.
--
-- #prune
-- The object system in the second version of GTK is based on GObject from
-- GLIB. This base class is rather primitive in that it only implements
-- ref and unref methods (and others that are not interesting to us). If
-- the marshall list mentions OBJECT it refers to an instance of this
-- GObject which is automatically wrapped with a ref and unref call.
-- Structures which are not derived from GObject have to be passed as
-- BOXED which gives the signal connect function a possiblity to do the
-- conversion into a proper ForeignPtr type. In special cases the signal
-- connect function use a PTR type which will then be mangled in the
-- user function directly. The latter is needed if a signal delivers a
-- pointer to a string and its length in a separate integer.
--
module System.Glib.Signals (
Signal(Signal),
on, after,
SignalName,
ConnectAfter,
ConnectId(ConnectId),
signalDisconnect,
signalBlock,
signalUnblock,
signalStopEmission,
disconnect,
GClosure,
#ifdef USE_GCLOSURE_SIGNALS_IMPL
connectGeneric,
#else
GClosureNotify,
mkFunPtrClosureNotify,
#endif
) where
import System.Glib.FFI
{#import System.Glib.GObject#}
#ifndef USE_GCLOSURE_SIGNALS_IMPL
import Data.IORef
#endif
{#context lib="glib" prefix="g" #}
newtype Signal object handler =
Signal (Bool -> object -> handler -> IO (ConnectId object))
-- | Perform an action in response to a signal.
--
-- Use it like this:
--
-- > on obj sig $ do
-- > ...
--
-- or if the signal handler takes any arguments:
--
-- > on obj sig $ \args -> do
-- > ...
--
on ::
object
-> Signal object callback
-> callback
-> IO (ConnectId object)
on object (Signal connect) handler = connect False object handler
-- | Perform an action in response to a signal.
--
-- * Like 'on' but the signal is executed after Gtk's default handler has
-- run.
--
after ::
object
-> Signal object callback
-> callback
-> IO (ConnectId object)
after object (Signal connect) handler = connect True object handler
-- Specify if the handler is to run before (False) or after (True) the
-- default handler.
type ConnectAfter = Bool
type SignalName = String
-- | The type of signal handler ids. If you ever need to 'disconnect' a signal
-- handler then you will need to retain the 'ConnectId' you got when you
-- registered it.
--
data GObjectClass o => ConnectId o = ConnectId {#type gulong#} o
-- old name for backwards compatability
disconnect :: GObjectClass obj => ConnectId obj -> IO ()
disconnect = signalDisconnect
{-# DEPRECATED disconnect "use signalDisconnect instead" #-}
-- | Disconnect a signal handler. After disconnecting the handler will no
-- longer be invoked when the event occurs.
--
signalDisconnect :: GObjectClass obj => ConnectId obj -> IO ()
signalDisconnect (ConnectId handler obj) =
withForeignPtr ((unGObject.toGObject) obj) $ \objPtr ->
{# call g_signal_handler_disconnect #} (castPtr objPtr) handler
-- | Block a specific signal handler.
--
-- * Blocks a handler of an instance so it will not be called during any
-- signal emissions unless it is unblocked again. Thus \"blocking\" a signal
-- handler means to temporarily deactive it, a signal handler has to be
-- unblocked exactly the same amount of times it has been blocked before
-- to become active again.
--
signalBlock :: GObjectClass obj => ConnectId obj -> IO ()
signalBlock (ConnectId handler obj) =
withForeignPtr ((unGObject.toGObject) obj) $ \objPtr ->
{# call g_signal_handler_block #} (castPtr objPtr) handler
-- | Unblock a specific signal handler.
--
-- * Undoes the effect of a previous 'signalBlock' call. A blocked handler
-- is skipped during signal emissions and will not be invoked, unblocking
-- it (for exactly the amount of times it has been blocked before) reverts
-- its \"blocked\" state, so the handler will be recognized by the signal
-- system and is called upon future or currently ongoing signal emissions
-- (since the order in which handlers are called during signal emissions
-- is deterministic, whether the unblocked handler in question is called
-- as part of a currently ongoing emission depends on how far that
-- emission has proceeded yet).
--
signalUnblock :: GObjectClass obj => ConnectId obj -> IO ()
signalUnblock (ConnectId handler obj) =
withForeignPtr ((unGObject.toGObject) obj) $ \objPtr ->
{# call g_signal_handler_unblock #} (castPtr objPtr) handler
-- | Stops a signal's current emission.
--
-- * This will prevent the default method from running. The sequence in which
-- handlers are run is \"first\", \"on\", \"last\" then \"after\" where
-- Gtk-internal
-- signals are connected either at \"first\" or at \"last\". Hence this
-- function can only stop the signal processing if it is called from within
-- a handler that is connected with an \"on\" signal and if the Gtk-internal
-- handler is connected as \"last\". Gtk prints a warning if this function
-- is used on a signal which isn't being emitted.
--
signalStopEmission :: GObjectClass obj => obj -> SignalName -> IO ()
signalStopEmission obj sigName =
withForeignPtr ((unGObject.toGObject) obj) $ \objPtr ->
withCString sigName $ \strPtr ->
{# call g_signal_stop_emission_by_name #} (castPtr objPtr) strPtr
{# pointer *GClosure newtype #}
#ifdef USE_GCLOSURE_SIGNALS_IMPL
connectGeneric :: GObjectClass obj =>
SignalName
-> ConnectAfter
-> obj
-> handler
-> IO (ConnectId obj)
connectGeneric signal after obj user = do
sptr <- newStablePtr user
gclosurePtr <- gtk2hs_closure_new sptr
sigId <-
withCString signal $ \signalPtr ->
withForeignPtr ((unGObject.toGObject) obj) $ \objPtr ->
{# call g_signal_connect_closure #}
(castPtr objPtr)
signalPtr
(GClosure gclosurePtr)
(fromBool after)
return $ ConnectId sigId obj
foreign import ccall unsafe "gtk2hs_closure_new"
gtk2hs_closure_new :: StablePtr a -> IO (Ptr GClosure)
#else
{#pointer GClosureNotify#}
foreign import ccall "wrapper" mkDestructor :: IO () -> IO GClosureNotify
mkFunPtrClosureNotify :: FunPtr a -> IO GClosureNotify
mkFunPtrClosureNotify hPtr = do
dRef <- newIORef nullFunPtr
dPtr <- mkDestructor $ do
freeHaskellFunPtr hPtr
dPtr <- readIORef dRef
freeHaskellFunPtr dPtr
writeIORef dRef dPtr
return dPtr
#endif