// -*- c++ -*-
dnl  signal.h.m4 - signal class for sigc++
dnl 
//   Copyright 2000, Karl Einar Nelson
dnl
dnl  This library is free software; you can redistribute it and/or
dnl  modify it under the terms of the GNU Lesser General Public
dnl  License as published by the Free Software Foundation; either
dnl  version 2 of the License, or (at your option) any later version.
dnl
dnl  This library is distributed in the hope that it will be useful,
dnl  but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
dnl  Lesser General Public License for more details.
dnl
dnl  You should have received a copy of the GNU Lesser General Public
dnl  License along with this library; if not, write to the Free Software
dnl  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
dnl
include(template.macros.m4)
#ifndef __header__
#define __header__
#include <sigc++/slot.h>
#include <sigc++/connection.h>
#include <sigc++/marshal.h>

#ifdef SIGC_CXX_NAMESPACES
namespace SigC
{
#endif

/** @defgroup Signals
 * Use connect() with SigC::slot to connect a method or function with a Signal.
 *
 * @code
 * signal_clicked.connect( SigC::slot(*this, &MyWindow::on_clicked) );
 * @endcode
 *
 * When the signal is emitted your method will be called.
 *
 * connect() returns a Connection, which you can later use to disconnect your method.
 *
 * When Signals are copied they share the underlying information,
 * so you can have a protected/private SigC::Signal member and a public accessor method.
 */

class SignalConnectionNode;
class SignalExec_;

class LIBSIGC_API SignalNode : public SlotNode
  {
    public:
      int exec_count_; // atomic
      SignalConnectionNode *begin_,*end_;

      SignalNode();
      ~SignalNode();

      // must be inline to avoid emission slowdowns.
      void exec_reference()
        { 
          reference();
          exec_count_ += 1;
        }

      // must be inline to avoid emission slowdowns.
      void exec_unreference()
        {
          exec_count_ -= 1;

          if (defered_ && !exec_count_)
            cleanup();

          unreference();
        }

      SlotNode* create_slot(FuncPtr proxy); // nothrow
      ConnectionNode* push_front(const SlotBase& s);
      ConnectionNode* push_back(const SlotBase& s);

      virtual void remove(SignalConnectionNode* c);
      bool empty();
      void clear();
      void cleanup(); // nothrow
   private:
      void _remove(SignalConnectionNode* c);
  };

class LIBSIGC_API SignalBase
  {
      friend class SignalConnectionNode;
    private:
      SignalBase& operator= (const SignalBase&); // no copy

    protected:
      typedef SignalExec_ Exec;

      mutable SignalNode *impl_;

      SlotNode* create_slot(FuncPtr c) const
        { return impl()->create_slot(c); }

      ConnectionNode* push_front(const SlotBase& s)
        { return impl()->push_front(s); }

      ConnectionNode* push_back(const SlotBase& s)
        { return impl()->push_back(s); }

      SignalBase();
      SignalBase(const SignalBase& s);
      SignalBase(SignalNode* s);
      ~SignalBase();

    public:
      bool empty() const
        { return !impl_ || impl()->empty(); }

      void clear()
        {
          if(impl_)
            impl()->clear();
        }

      SignalNode* impl() const;
  };

class LIBSIGC_API SignalConnectionNode : public ConnectionNode
  {
    public:
      virtual void notify(bool from_child);

      virtual ~SignalConnectionNode();
      SignalConnectionNode(SlotNode*);
  
      SignalNode *parent_;
      SignalConnectionNode *next_,*prev_;
      
      SlotNode* dest() { return (SlotNode*)(slot().impl()); }
  };

// Exeception-safe class for tracking signals.
class LIBSIGC_API SignalExec_
  {
  public:
    SignalNode* signal_;

    SignalExec_(SignalNode* signal) :signal_(signal)
      { signal_->exec_reference(); }

    ~SignalExec_()
      { signal_->exec_unreference(); }
  };
    

/********************************************************/

define([__SIGNAL__],[[Signal]eval(NUM($*)-2)<LIST($*)>])dnl
dnl
dnl  SIGNAL([P1..PN], R)
dnl
define([SIGNAL],[dnl
define([_R_],ifelse($2,void, void, R))
ifelse($2,void, [dnl
/// @ingroup Signals
template <LIST(ARG_CLASS($1), class Marsh)>
class __SIGNAL__(void, $1, Marsh) : public SignalBase
],[dnl
/// @ingroup Signals
template <LIST(class R,ARG_CLASS($1),class Marsh=Marshal<R>) >
class Signal[]NUM($1) : public SignalBase
])dnl
  {
    public:
      typedef Slot[]NUM($1)<LIST(_R_, [$1])> InSlotType;
ifelse($2,void, [dnl
      typedef InSlotType OutSlotType;
      typedef void OutType;
],[dnl
      typedef Slot[]NUM($1)<LIST(typename Marsh::OutType, [$1])> OutSlotType;
      typedef typename Trait<typename Marsh::OutType>::type OutType;
])dnl
 
    private:
      // Used for both emit and proxy.
      static OutType emit_(LIST(ARG_REF($1), void* data));

    public:
      OutSlotType slot() const
        { return create_slot((FuncPtr)(&emit_)); }

      operator OutSlotType() const
        { return create_slot((FuncPtr)(&emit_)); }

      /// You can call Connection::disconnect() later.
      Connection connect(const InSlotType& s)
        { return Connection(push_back(s)); }

      /// Call all the connected methods.
      OutType emit(ARG_REF($1))
        { ifelse($2,void, ,return) emit_(LIST(ARG_NAME($1), impl_)); }

      /// See emit()
      OutType operator()(ARG_REF($1))
        { ifelse($2,void, ,return) emit_(LIST(ARG_NAME($1), impl_)); }
 
      Signal[]NUM($1)() 
        : SignalBase() 
        {}

      Signal[]NUM($1)(const InSlotType& s)
        : SignalBase() 
        { connect(s); }

      ~Signal[]NUM($1)() {}
  };


// emit
ifelse($2,void, [dnl
template <LIST(ARG_CLASS($1),class Marsh)>
void __SIGNAL__(void, $1, Marsh)::emit_(LIST(ARG_REF($1), void* data))
  {
    SignalNode* impl = static_cast<SignalNode*>(data);

    if (!impl||!impl->begin_)
      return;

    Exec exec(impl);
    SlotNode* s = 0;
    for (SignalConnectionNode* i = impl->begin_; i; i = i->next_)
      {
        if (i->blocked())
          continue;

        s = i->dest();
        ((typename __SLOT__(void, $1)::Proxy)(s->proxy_))(LIST(ARG_NAME($1), s));
      }
    return;
  }
],[dnl
template <LIST(class R, ARG_CLASS($1), class Marsh)>
typename __SIGNAL__(_R_, $1, Marsh)::OutType
__SIGNAL__(_R_, $1, Marsh)::emit_(LIST(ARG_REF($1), void* data))
  {
    SignalNode* impl = static_cast<SignalNode*>(data);

    if (!impl || !impl->begin_)
      return Marsh::default_value();

    Exec exec(impl);
    Marsh rc;
    SlotNode* s = 0;

    for (SignalConnectionNode* i = impl->begin_; i; i=i->next_)
      {
        if (i->blocked()) continue;
        s = i->dest();
        if (rc.marshal(((typename __SLOT__(R,$1)::Proxy)(s->proxy_))(LIST(ARG_NAME($1), s))))
          return rc.value();
      }
    return rc.value();
  }
])dnl

])

SIGNAL(ARGS(P,0))
SIGNAL(ARGS(P,1))
SIGNAL(ARGS(P,2))
SIGNAL(ARGS(P,3))
SIGNAL(ARGS(P,4))
SIGNAL(ARGS(P,5))

#ifdef SIGC_CXX_PARTIAL_SPEC

SIGNAL(ARGS(P,0),void)
SIGNAL(ARGS(P,1),void)
SIGNAL(ARGS(P,2),void)
SIGNAL(ARGS(P,3),void)
SIGNAL(ARGS(P,4),void)
SIGNAL(ARGS(P,5),void)
#endif



#ifdef SIGC_CXX_NAMESPACES
}
#endif

#endif // __header__


syntax highlighted by Code2HTML, v. 0.9.1