diff qt/d2/qt/Signal.d @ 288:f9559a957be9 signals

new signals and slots implementation
author eldar
date Sun, 08 Nov 2009 19:28:01 +0000
parents 1f6923c8cba0
children c9d1aac290e9
line wrap: on
line diff
--- a/qt/d2/qt/Signal.d	Sun Nov 08 19:20:53 2009 +0000
+++ b/qt/d2/qt/Signal.d	Sun Nov 08 19:28:01 2009 +0000
@@ -12,856 +12,137 @@
 module qt.Signal;
 
 public import qt.QGlobal;
-public import
-    std.metastrings,
-    std.typetuple;
+import qt.qtd.MetaMarshall;
+
 import core.stdc.stdlib : crealloc = realloc, cfree = free;
 import core.stdc.string : memmove;
 import
-    std.traits,
     core.thread,
-    core.exception;
-
-private: // private by default
-
-alias void delegate(Object) DEvent;
-
-extern(C) void rt_attachDisposeEvent(Object o, DEvent e);
-extern(C) void rt_detachDisposeEvent(Object o, DEvent e);
-extern(C) Object _d_toObject(void* p);
-
-void realloc(T)(ref T[] a, size_t length)
-{
-    a = (cast(T*)crealloc(a.ptr, length * T.sizeof))[0..length];
-    if (!a.ptr)
-        new OutOfMemoryError(__FILE__, __LINE__);
-}
+    core.exception,
+    std.algorithm;
 
-
-void append(T)(ref T[] a, T element)
-{
-    auto newLen = a.length + 1;
-    a = (cast(T*)crealloc(a.ptr, newLen * T.sizeof))[0..newLen];
-    if (!a.ptr)
-        new OutOfMemoryError(__FILE__, __LINE__);
-    a[newLen - 1] = element;
-}
+public import
+    std.typetuple,
+    std.traits,
+    std.conv,
+    std.string,
+    std.metastrings;
 
-void move(T)(ref T[] a, size_t src, size_t dest, size_t length)
-{
-    if (a.length > 1)
-        memmove(a.ptr + dest, a.ptr + src, length * T.sizeof);
-}
-
-// COMPILER BUG: Though this is private cannot name it 'remove' because of conflicts
-// with Array.remove
-void erase(T)(ref T[] a, size_t i) 
+   
+// returns name, arguments or tuple of the function depending on type parameter
+enum {_Name, _Tuple, _Args}
+string getFunc(int type)(string fullName)
 {
-    auto newLen = a.length - 1;
-    move(a, i + 1, i, newLen);
-    realloc(a, newLen);
-}
-
-version (QtdUnittest)
-{
-    unittest
-    {
-        int[] a;
-        realloc(a, 16);
-        assert(a.length == 16);
-        foreach (i, ref e; a)
-            e = i;
-        realloc(a, 4096);
-        assert(a.length == 4096);
-        foreach (i, e; a[0..16])
-            assert(e == i);
-        cfree(a.ptr);
-    }
-}
-
-//TODO: should be in the standard library
-struct STuple(A...)
-{
-    static string genSTuple()
-    {
-        string r = "";
-        foreach (i, e; A)
-            r ~= A[i].stringof ~ " _" ~ ToString!(i) ~ ";";
-        return r;
-    }
-
-    mixin (genSTuple);
-    template at(size_t i) { mixin("alias _" ~ ToString!(i) ~ " at;"); };
-}
-
-enum SignalEventId
-{
-    firstSlotConnected,
-    lastSlotDisconnected
+    int pos = 0;
+    foreach(i, c; fullName)
+        if (c == '(')
+            static if (type == _Tuple)
+                return fullName[i..$];
+            else if (type == _Name)
+                return fullName[0..i];
+            else if (type == _Args)
+                for(int j = fullName.length-1;; j--)
+                    if(fullName[j] == ')')
+                        return fullName[i+1 .. j];
+    return null;
 }
 
-public class SignalException : Exception
+/** The beast that takes string representation of function arguments
+  * and returns an array of default values it doesn't check if arguments
+  * without default values follow the arguments with default values for
+  * simplicity. It is done by mixing in an delegate alias.
+  */
+string[] defaultValues(string signature)
 {
-    this(string msg)
-    {
-        super(msg);
-    }
-}
-
-struct Fn
-{
-    void* funcptr;
-
-    static typeof(this) opCall(R, A...)(R function(A) fn)
-    {
-        typeof(this) r;
-        r.funcptr = fn;
-        return r;
-    }
+    int braces = 0;
+    bool inDefaultValue = false;
+    bool inStringLiteral = false;
+    string[] res;
+    int startValue = 0;
+    
+    if(strip(signature).length == 0)
+        return res;
 
-    template call(R)
-    {
-        R call(A...)(A args)
-        {
-            alias R function(A) Fn;
-            return (cast(Fn)funcptr)(args);
-        }
-    }
-
-    S get(S)()
-    {
-        static assert (is(typeof(*S.init) == function));
-        return cast(S)funcptr;
-    }
-}
-
-struct Dg
-{
-    void* context;
-    void* funcptr;
-
-    static typeof(this) opCall(R, A...)(R delegate(A) dg)
+    foreach (i,c; signature)
     {
-        typeof(this) r;
-        r.context = dg.ptr;
-        r.funcptr = dg.funcptr;
-        return r;
-    }
-
-    template call(R)
-    {
-        R call(A...)(A args)
+        if(!inStringLiteral)
         {
-            R delegate(A) dg; // BUG: parameter storage classes are ignored
-            dg.ptr = context;
-            dg.funcptr = cast(typeof(dg.funcptr))funcptr;
-            return dg(args);
-        }
-    }
-
-    S get(S)()
-    {
-        static assert (is(S == delegate));
-        S r;
-        r.ptr = context;
-        r.funcptr = cast(typeof(r.funcptr))funcptr;
-        return r;
-    }
-}
-
-struct Slot(R)
-{
-    alias R Receiver;
-
-    Receiver receiver;
-    Dg invoker;
-    ConnectionFlags flags;
-    
-    static if (is(Receiver == Dg))
-    {
-        static const isDelegate = true;
-                
-        bool isDisposed()
-        {
-            return !receiver.funcptr;
-        }
-        
-        void dispose()
-        {
-            receiver.funcptr = null;
-            receiver.context = null;
+            if(c == '{' || c =='(')
+                braces++;
+            else if(c == '}' || c ==')')
+                braces--;
         }
 
-        Object getObject()
-        {           
-            return flags & ConnectionFlags.NoObject || !receiver.context
-                ? null : _d_toObject(receiver.context);
-        }
-    }
-    else
-        static const isDelegate = false;
-}
-
-enum SlotListId
-{
-    Func, // function pointers
-    Weak, // object delegates stored in C heap
-    Strong // delegates stored in GC heap
-}
-
-/**
-    Used to specify the type of a signal-to-slot connection.
-
-    Examples:
-----
-class Sender
-{
-    mixin Signal!("changed");
-    void change()
-    {
-        changed.emit;
-    }
-}
-
-
-class Receiver
-{
-    void alarm() {}
-}
-
-void main()
-{
-    auto s = new Sender;
-    auto r = new Receiver;
-    s.changed.connect(&r.alarm); // now s weakly references r
-
-    r = null;
-    // collect garbage (assume there is no more reachable pointers
-    // to the receiver and it gets finalized)
-    ...
-
-    s.change;
-    // weak reference to the receiving object
-    // has been removed from the sender's connection lists.
-
-    r = new Receiver;
-    s.changed.connect(&r.alarm, ConnectionFlags.Strong);
-
-    r = null;
-    // collect garbage
-    ...
-    // the receiving object has not been finalized because s strongly references it.
-
-    s.change; // the receiver is called.
-    delete r;
-    s.change; // the receiver is disconnected from the sender.
-
-    static void foo()
-    {
-    }
-
-    s.changed.connect(&foo);
-    s.changed.emit; // foo is called.
-    s.changed.disconnect(&foo); // must be explicitly disconnected.
-
-    void bar()
-    {
-    }
-
-    // ConnectionFlags.NoObject must be specified for delegates
-    // to non-static local functions or struct member functions.
-    s.changed.connect(&bar, ConnectionFlags.NoObject);
-    s.changed.emit; // bar is called.
-    s.changed.disconnect(&bar); // must be explicitly disconnected.
-}
-----
-*/
-public enum ConnectionFlags : ubyte
-{
-    ///
-    None,
-    /**
-        The receiver will be stored as weak reference (implied if ConnectionFlags.NoObject is not specified).
-        If the signal receiver is not a function pointer or a delegate referencing a D class instance.
-        the sender will not be notified when the receiving object is deleted and emitting the signal
-        connected to that receiving object will result in undefined behavior.
-    */
-    Weak                = 0x0001,
-    /**
-        The receiver is stored as strong reference (implied if ConnectionFlags.NoObject is specified).
-    */
-    Strong              = 0x0002,
-    /**
-        Must be specified if the receiver is not a function pointer or a delegate referencing a D class instance.
-    */
-    NoObject            = 0x0004
-
-    // Queued           = 0x0004,
-    // BlockingQueued   = 0x0008
-}
-
-
-struct SlotList(SlotT, bool strong = false)
-{
-    alias SlotT SlotType;
-    SlotType[] data;
-
-    void length(size_t length)
-    {
-        static if (strong)
-            data.length = length;
-        else
-            realloc(data, length);
-    }
-
-    SlotType* add(SlotType slot)
-    {
-        auto oldLen = data.length;
-        length = oldLen + 1;
-        auto p = &data[oldLen];
-        *p = slot;
-        return p;
-    }
-
-    SlotType* get(int slotId)
-    {
-        return &data[slotId];
-    }
-
-    void remove(int slotId)
-    {
-        move(data, slotId, slotId + 1, data.length - slotId - 1);
-        data = data[0..$ - 1];
-    }
-
-    size_t length()
-    {
-        return data.length;
-    }
-
-    void free()
-    {
-        static if (!strong)
-            cfree(data.ptr);
-    }
-}
-
-public alias void delegate(int signalId, SignalEventId event) SignalEvent;
-
-struct Receivers
-{
-    struct Data
-    {
-        Object object;
-        int refs;
-    }
-    
-    Data[] data;
-    void add(Object receiver, DEvent disposeEvent)
-    {        
-        foreach (ref d; data)
+        if(c == '\"' || c == '\'')
         {
-            if (d.object is receiver)
-            {               
-                d.refs++;              
-                return;
+            if (inStringLiteral)
+            {
+                if(signature[i-1] != '\\')
+                    inStringLiteral = false;
+            }
+            else
+            {
+                inStringLiteral = true;
             }
         }
         
-        append(data, Data(receiver, 1));
-        rt_attachDisposeEvent(receiver, disposeEvent);
-    }
-    
-    void remove(Object receiver, DEvent disposeEvent)
-    {
-        foreach (i, ref d; data)
+        if (!inStringLiteral && braces == 0)
         {
-            if (d.object is receiver)
+            if(c == '=') // found default value
             {
-                assert (d.refs);
-                d.refs--;
-                if (!d.refs)
+                inDefaultValue = true;
+                startValue = i+1;
+            }
+            else if(c == ',') // next function argument
+            {
+                if (inDefaultValue)
                 {
-                    .erase(data, i);                    
-                    rt_detachDisposeEvent(receiver, disposeEvent);
+                    res ~= signature[startValue..i];
+                    inDefaultValue = false;
                 }
-                return;
-            }
-        }
-        
-        assert (false);
-    }
-    
-    // remove all refarences for receiver, receiver has been disposed
-    void removeAll(Object receiver)
-    {
-        foreach (i, ref d; data)
-        {
-            if (d.object is receiver) 
-            {
-                .erase(data, i);
-                return;
             }
         }
     }
     
-    // remove all references for all receivers, detaching dispose events
-    void free(DEvent disposeEvent)
-    {
-        foreach (i, ref d; data)
-            rt_detachDisposeEvent(d.object, disposeEvent);
-        cfree(data.ptr);
-        data = null;
-    }
-}
-
-struct SignalConnections
-{
-    bool isInUse;
-
-    STuple!(
-        SlotList!(Slot!(Fn)),
-        SlotList!(Slot!(Dg)),
-        SlotList!(Slot!(Dg), true)
-    ) slotLists;
-
-    STuple!(
-        Fn[],
-        Dg[]
-    ) delayedDisconnects;
-
-    void addDelayedDisconnect(Fn r)
-    {
-        delayedDisconnects.at!(0) ~= r;
-    }
-
-    void addDelayedDisconnect(Dg r)
-    {
-        delayedDisconnects.at!(1) ~= r;
-    }
-
-    SlotListType!(slotListId)* getSlotList(int slotListId)()
-    {
-        return &slotLists.tupleof[slotListId];
-    }
-
-    bool hasSlots()
-    {
-        foreach(i, e; slotLists.tupleof)
-        {
-            if (slotLists.tupleof[i].length)
-                return true;
-        }
-        return false;
-    }
-
-    int slotCount()
-    {
-        int count;
-        foreach(i, e; slotLists.tupleof)
-            count += slotLists.at!(i).length;
-        return count;
-    }
+    if (inDefaultValue)
+        res ~= signature[startValue..$];
 
-    void slotListLengths(int[] lengths)
-    {
-        foreach(i, e; slotLists.tupleof)
-             lengths[i] = slotLists.at!(i).length;
-    }
-
-    SlotType!(slotListId)* addSlot(int slotListId)(SlotType!(slotListId) slot)
-    {
-        return getSlotList!(slotListId).add(slot);
-    }
-
-    void removeSlot(int slotListId)(int slotId)
-    {
-        slotLists.at!(slotListId).remove(slotId);
-    }
-
-    void free()
-    {
-        foreach(i, e; slotLists.tupleof)
-        {
-            static if (is(typeof(slotLists.at!(i).free)))
-                slotLists.at!(i).free;
-        }
-    }
-    
-    void onReceiverDisposed(Object receiver)
-    {
-        foreach (i, e; slotLists.tupleof)
-        {
-            static if (slotLists.at!(i).SlotType.isDelegate)
-            {
-                foreach (ref slot; slotLists.at!(i).data)
-                {
-                    if (slot.getObject is receiver)
-                        slot.dispose;
-                }
-            }
-        }
-    }
-
-    template SlotListType(int slotListId)
-    {
-        alias typeof(slotLists.tupleof)[slotListId] SlotListType;
-    }
-
-    template SlotType(int slotListId)
-    {
-        alias SlotListType!(slotListId).SlotType SlotType;
-    }
-
-    template ReceiverType(int slotListId)
-    {
-        alias SlotType!(slotListId).Receiver ReceiverType;
-    }
-
-    static const slotListCount = slotLists.tupleof.length;
-}
-
-
-private Object signalSender_;
-
-/**
-    If called from a slot, returns the object
-    that is emitting the signal. Otherwise, returns null.
-*/
-public Object signalSender() {
-    return signalSender_;
+    return res;
 }
 
-public final class SignalHandler
+int defaultValuesLength(string[] defVals)
 {
-    SignalConnections[] connections;
-    Receivers receivers;
-    Object owner;
-    int blocked;
-    
-    SignalEvent signalEvent;
-       
-    alias SignalConnections.SlotType SlotType;
-    alias SignalConnections.ReceiverType ReceiverType;
-
-    public this(Object owner_) {
-        owner = owner_;
-    }
-
-    private SignalConnections* getConnections(int signalId)
-    {
-        if (signalId < connections.length)
-            return &connections[signalId];
-        return null;
-    }
-
-    private SlotType!(slotListId)* addSlot(int slotListId)(int signalId, ReceiverType!(slotListId) receiver,
-        Dg invoker, ConnectionFlags flags)
-    {
-        if (signalId >= connections.length)
-            connections.length = signalId + 1;
-        auto slot = connections[signalId].addSlot!(slotListId)(SlotType!(slotListId)(receiver, invoker));
-        
-        static if (slot.isDelegate)
-        {
-            if (!(flags & ConnectionFlags.NoObject))
-                receivers.add(_d_toObject(receiver.context), &onReceiverDisposed);
-        }
-
-        if (signalEvent && connections[signalId].slotCount == 1)
-            signalEvent(signalId, SignalEventId.firstSlotConnected);
-
-        return slot;
-    }
-    
-    void onReceiverDisposed(Object receiver)
-    {
-        synchronized(this)
-        {
-            foreach(ref c; connections)
-                c.onReceiverDisposed(receiver);
-            receivers.removeAll(receiver);
-        }
-    }
-
-    private void removeSlot(int slotListId)(int signalId, int slotId)
-    {
-        auto slot = connections[signalId].getSlotList!(slotListId).get(slotId);
-        static if (slot.isDelegate)
-        {
-            if (auto obj = slot.getObject)
-                receivers.remove(obj, &onReceiverDisposed);
-        }
-        
-        connections[signalId].removeSlot!(slotListId)(slotId);
-
-        if (signalEvent && !connections[signalId].slotCount)
-            signalEvent(signalId, SignalEventId.lastSlotDisconnected);
-    }
-
-    size_t slotCount(int signalId)
-    {
-        synchronized(this)
-        {
-            auto con = getConnections(signalId);
-            if (con)
-                return con.slotCount;
-            return 0;
-        }
-    }
-
-    void connect(Receiver)(int signalId, Receiver receiver,
-        Dg invoker, ConnectionFlags flags)
-    {
-        synchronized(this)
-        {
-            static if (is(typeof(receiver.context)))
-            {
-                Object obj;
-                if ((flags & ConnectionFlags.NoObject))
-                {
-                    // strong by default
-                    if (flags & ConnectionFlags.Weak)
-                        addSlot!(SlotListId.Weak)(signalId, receiver, invoker, flags);
-                    else
-                        addSlot!(SlotListId.Strong)(signalId, receiver, invoker, flags);
-                }
-                else
-                {
-                    // weak by default
-                    if (flags & ConnectionFlags.Strong)
-                        addSlot!(SlotListId.Strong)(signalId, receiver, invoker, flags);
-                    else
-                        addSlot!(SlotListId.Weak)(signalId, receiver, invoker, flags);
-                }
-            }
-            else
-                addSlot!(SlotListId.Func)(signalId, receiver, invoker, flags);
-        }
-    }
-
-    void disconnect(Receiver)(int signalId, Receiver receiver)
-    {
-        synchronized(this)
-        {
-            auto cons = getConnections(signalId);
-            if (!cons)
-                return;
-
-            // if called from a slot being executed by this signal, delay disconnection
-            // until all slots has been called.
-            if (cons.isInUse)
-            {
-                cons.addDelayedDisconnect(receiver);
-                return;
-            }
-
-        TOP:
-            foreach (slotListId, e; cons.slotLists.tupleof)
-            {
-                /// COMPILER BUG: ReceiverType is evaluated to expression instead of type.
-                static if (is(typeof(cons.ReceiverType!(slotListId)) == Receiver))
-                {
-                    auto slotList = cons.getSlotList!(slotListId);
-                    for (int slotId; slotId < slotList.length;)
-                    {
-                        auto slot = slotList.get(slotId);
-                        static if (slot.isDelegate)
-                        {
-                            if (slot.isDisposed)
-                            {
-                                removeSlot!(slotListId)(signalId, slotId);
-                                continue;
-                            }
-                        }
-
-                        if (slot.receiver == receiver)
-                        {
-                            removeSlot!(slotListId)(signalId, slotId);
-                            break TOP;
-                        }
-
-                        slotId++;
-                    }
-                }
-            }
-        }
-    }
-
-    void emit(A...)(size_t signalId, A args)
-    {
-        synchronized(this)
-        {
-            if (signalId >= connections.length || blocked)
-                return;
-            auto cons = &connections[signalId];
-
-            if (cons.hasSlots)
-            {
-                {
-                    cons.isInUse = true;
-                    signalSender_ = owner;
-                    scope(exit)
-                    {
-                        cons.isInUse = false;
-                        signalSender_ = null;
-                    }
-
-                    // Store the lengths to avoid calling new slots
-                    // connected in the slots being called.
-                    // dmd bug: int[cons.slotListCount] fails
-                    static const c = cons.slotListCount;
-                    int[c] lengths = void;
-                    cons.slotListLengths(lengths);
-
-                    foreach (slotListId, e; cons.slotLists.tupleof)
-                    {
-                        auto slotList = cons.getSlotList!(slotListId);
-                        for (size_t slotId; slotId < lengths[slotListId];)
-                        {
-                            auto slot = slotList.get(slotId);
-                            static if (slot.isDelegate)
-                            {
-                                if (slot.isDisposed)
-                                {
-                                    removeSlot!(slotListId)(signalId, slotId);
-                                    lengths[slotListId]--;
-                                    continue;
-                                }
-                            }
-
-                            slot.invoker.call!(void)(slot.receiver, args);
-                            ++slotId;
-                        }
-                    }
-                }
-
-
-                // process delayed disconnects if any
-                foreach(i, e; cons.delayedDisconnects.tupleof)
-                {
-                    if (cons.delayedDisconnects.at!(i).length)
-                    {
-                        foreach (d; cons.delayedDisconnects.at!(i))
-                            disconnect(signalId, d);
-                        cons.delayedDisconnects.at!(i).length = 0;
-                    }
-                }
-            }
-        }
-    }
-
-    // Adjusts signal arguments and calls the slot. S - slot signature, A - signal arguments
-    private void invokeSlot(S, Receiver, A...)(Receiver r, A args)
-    {
-        r.get!(S)()(args[0..ParameterTypeTuple!(S).length]);
-    }
-
-    void blockSignals()
-    {
-        synchronized(this)
-            blocked++;
-    }
-
-    void unblockSignals()
-    {
-        synchronized(this)
-        {
-            if(!blocked)
-                throw new SignalException("Signals are not blocked");
-            blocked--;
-        }
-    }
-
-    ~this()
-    {
-        receivers.free(&onReceiverDisposed);
-        foreach(ref c; connections)
-            c.free;
-    }
-}
-
-public template SignalHandlerOps()
-{
-    static assert (is(typeof(this.signalHandler)),
-        "SignalHandlerOps is already instantiated in " ~ typeof(this).stringof ~ " or one of its base classes");
-
-protected:
-    SignalHandler signalHandler_; // manages signal-to-slot connections
-
-    final SignalHandler signalHandler()
-    {
-        if (!signalHandler_)
-        {
-            signalHandler_ = new SignalHandler(this);
-            onSignalHandlerCreated(signalHandler_);
-        }
-        return signalHandler_;
-    }
-
-    void onSignalHandlerCreated(ref SignalHandler sh)
-    {
-    }
-
-public:
-    final void blockSignals()
-    {
-        signalHandler.blockSignals();
-    }
-
-    final void unblockSignals()
-    {
-        signalHandler.unblockSignals();
-    }
-
-    template connect(string signalName, A...)
-    {
-        static void connect(T, Func)(T sender, Func func, ConnectionFlags flags = ConnectionFlags.None)
-            if (isFnOrDg!(Func))
-        {
-            alias findSignal!(T, signalName, Func, A).result sig;
-            auto sh = sender.signalHandler();
-            static if (isFn!(Func))
-                alias Fn Callable;
-            else
-                alias Dg Callable;
-            auto invoker = Dg(&sh.invokeSlot!(typeof(func), Callable, sig[2..$]));
-            sh.connect(sig[1], Callable(func), invoker, flags);
-        }
-    }
-
-    template disconnect(string signalName, A...)
-    {
-        static void connect(T, Func)(T sender, Func func, ConnectionFlags flags = ConnectionFlags.None)
-            if (isFnOrDg!(Func))
-        {
-            alias findSignal!(T, signalName, Func, A).result sig;
-            auto sh = sender.signalHandler();
-            static if (isFn!(Func))
-                alias Fn Callable;
-            else
-                alias Dg Callable;
-            sh.disconnect(sig[1], Callable(func));
-        }
-    }
-/*
-    template slotCount(string signalName, A...)
-    {
-        debug static void slotCount(T)(T sender)
-        {
-            alias findSignal!(T, signalName, Func, A).result sig;
-            auto sh = sender.signalHandler();
-            return sh.slotCount(sig[1]);
-        }
-    }
-    */
+    return defVals.length;
 }
 
 /**
     New implementation.
 */
 
-const string signalPrefix = "__signal";
+
+// need this to mark static metamethods-info whether it's generated by presence of default args
+enum DefaultArgs
+{
+    None, Start, Continue
+}
+
+// templates for extracting data from static meta-information of signals, slots or properties
+// public alias TypeTuple!("name", index, OwnerClass, DefaultArgs.Start, ArgTypes) __signal
+template MetaEntryName(source...)
+{
+    enum MetaEntryName = source[0]; // name of the metaentry is the first element
+}
+
+template MetaEntryOwner(source...)
+{
+    alias TupleWrapper!(source[2]).at[0] MetaEntryOwner; // class that owns the property is the third
+    // Compiler #BUG 3092 - evaluates MetaEntryOwner as a Tuple with one element
+}
+
+template MetaEntryArgs(source...)
+{
+    alias source[4 .. $] MetaEntryArgs; // arguments-tuple starts from the fourth position
+}
 
 template TupleWrapper(A...) { alias A at; }
 
@@ -955,6 +236,14 @@
     }
 }
 
+template ByOwner(Owner)
+{
+    template ByOwner(source...)
+    {
+        enum ByOwner = is(MetaEntryOwner!source == Owner);
+    }
+}
+
 template staticSymbolName(string prefix, int id)
 {
     const string staticSymbolName = prefix ~ ToString!(id);
@@ -965,6 +254,7 @@
     const string signatureString = name ~ "(" ~ joinArgs!(A) ~ ")";
 }
 
+// recursive search in the static meta-information
 template findSymbolImpl(string prefix, C, int id, alias pred)
 {
     static if ( is(typeof(mixin("C." ~ staticSymbolName!(prefix, id)))) )
@@ -1006,6 +296,30 @@
     }
 }
 
+// recursive search in the static meta-information
+template findSymbolsImpl(string prefix, C, int id, alias pred)
+{
+    static if ( is(typeof(mixin("C." ~ staticSymbolName!(prefix, id)))) )
+    {
+        mixin ("alias C." ~ staticSymbolName!(prefix, id) ~ " current;");
+        static if (pred!current) {
+            alias TupleWrapper!current subres;
+//                    pragma(msg, toStringNow!id ~ " " ~ subres.stringof);
+        } else
+            alias TypeTuple!() subres;
+        alias TypeTuple!(subres, findSymbolsImpl!(prefix, C, id + 1, pred).result) result;
+    }
+    else
+    {
+        alias TypeTuple!() result;
+    }
+}
+
+template findSymbols(string prefix, C, alias pred)
+{
+    alias findSymbolsImpl!(prefix, C, 0, pred).result findSymbols;
+}
+
 string __toString(long v)
 {
     if (v == 0)
@@ -1032,18 +346,42 @@
     return ret;
 }
 
-public string SignalEmitter(A...)(SignalType signalType, string name, int index)
+string convertSignalArguments(Args...)()
+{
+//        void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
+
+    string res = "void*[" ~ __toString(Args.length+1) ~ "] _a = [null";
+    foreach(i, _; Args)
+        res ~= ", " ~ "cast(void*) &" ~ convertSignalArgument!(Args[i])("_t" ~ __toString(i));
+    res ~= "];\n";
+    return res;
+}
+
+public string SignalEmitter(A...)(SignalType signalType, string name, string[] defVals, int localIndex)
 {
     string fullArgs, args;
+    int defValsLength = defVals.length;
+    string argsConversion = "";
+    string argsPtr = "null";
     static if (A.length)
     {
-        fullArgs = A[0].stringof ~ " a0";
-        args = ", a0";
+        while(A.length != defVals.length)
+            defVals = "" ~ defVals;
+        
+        fullArgs = A[0].stringof ~ " _t0";
+        if (defVals[0].length)
+            fullArgs ~= " = " ~ defVals[0];
+        args = "_t0";
         foreach(i, _; A[1..$])
         {
-            fullArgs ~= ", " ~ A[i+1].stringof ~ " a" ~ __toString(i+1);
-            args ~= ", a" ~ __toString(i+1);
+            fullArgs ~= ", " ~ A[i+1].stringof ~ " _t" ~ __toString(i+1);
+            if (defVals[i+1].length)
+                fullArgs ~= " = " ~ defVals[i+1];
+            args ~= ", _t" ~ __toString(i+1);
         }
+        // build up conversion of signal args from D to C++
+        argsPtr = "_a.ptr";
+        argsConversion = convertSignalArguments!(A)();
     }
     string attribute;
     string sigName = name;
@@ -1051,197 +389,147 @@
         name ~= "_emit";
     else
         attribute = "protected ";
-    string str = attribute ~ "void " ~ name ~ "(" ~ fullArgs ~ ")" ~
-                 "{ this.signalHandler.emit(" ~ __toString(index) ~ args ~ "); }";
+    
+    string indexArgs = __toString(localIndex);
+    if(defValsLength > 0)
+        indexArgs ~= ", " ~ __toString(localIndex+defValsLength);
+    string str = attribute ~ "final void " ~ name ~ "(" ~ fullArgs ~ ") {\n" ~ argsConversion ~ "\n"
+                           ~ "    QMetaObject.activate(this, typeof(this).staticMetaObject, " ~ indexArgs ~ ", " ~ argsPtr ~ ");\n"
+                           ~ "}\n"; // ~
     return str;
 }
-
 /** ---------------- */
 
 
-/**
-    Examples:
-----
-struct Args
-{
-    bool cancel;
-}
-
-class C
-{
-    private int _x;
-    // reference parameters are not supported yet,
-    // so we pass arguments by pointer.
-    mixin Signal!("xChanging", int, Args*);
-    mixin Signal!("xChanged");
-
-    void x(int v)
-    {
-        if (v != _x)
-        {
-            Args args;
-            xChanging.emit(v, &args);
-            if (!args.cancel)
-            {
-                _x = v;
-                xChanged.emit;
-            }
-        }
-    }
-}
-----
-*/
+const string signalPrefix = "__signal";
+const string slotPrefix = "__slot";
 
 enum SignalType
 {
     BindQtSignal,
-    NewSignal
-}
-
-template BindQtSignal(string name, A...)
-{
-    mixin SignalImpl!(0, name, SignalType.BindQtSignal, A);
-}
-
-template Signal(string name, A...)
-{
-    mixin SignalImpl!(0, name, SignalType.NewSignal, A);
+    NewSignal,
+    NewSlot
 }
 
-template SignalImpl(int index, string name, SignalType signalType, A...)
+template BindQtSignal(string fullName)
 {
-    static if (is(typeof(mixin(typeof(this).stringof ~ ".__signal" ~ ToString!(index)))))
-        mixin SignalImpl!(index + 1, name, signalType, A);
-    else
-    {
-        // mixed-in once
-        static if (!is(typeof(this.signalHandler)))
-            mixin SignalHandlerOps;
-
-        mixin (SignalEmitter!(A)(signalType, name, index));
-        mixin("public alias TypeTuple!(\"" ~ name ~ "\", index, A) __signal" ~ ToString!(index) ~ ";");
-    }
+    mixin MetaMethodImpl!(signalPrefix, 0, fullName, SignalType.BindQtSignal);
 }
 
-extern(C) alias void function(void*) SlotConnector;
-
-debug (UnitTest)
+template Signal(string fullName)
 {
-    class A
-    {
-        mixin Signal!("scorched", int);
-
-        int signalId1 = -1;
-        int signalId2 = -1;
-
-        void onFirstConnect(int sId)
-        {
-            signalId1 = sId;
-        }
-
-        void onLastDisconnect(int sId)
-        {
-            signalId2 = sId;
-        }
+    mixin MetaMethodImpl!(signalPrefix, 0, fullName, SignalType.NewSignal);
+}
 
-        this()
-        {
-            signalHandler.firstSlotConnected = &onFirstConnect;
-            signalHandler.lastSlotDisconnected = &onLastDisconnect;
-        }
-    }
-
-    class B : A
-    {
-        mixin Signal!("booed", int);
-
-        int bazSum;
-        void baz(int i)
-        {
-            bazSum += i;
-        }
-    }
-
-    class C : A
-    {
-        mixin Signal!("cooked");
-    }
+template Slot(string fullName)
+{
+    mixin MetaMethodImpl!(slotPrefix, 0, fullName, SignalType.NewSlot);
 }
 
-unittest
+template SignalImpl(int index, string fullName, SignalType signalType)
 {
-    static int fooSum;
-    static int barSum;
-
-    static void foo(int i)
-    {
-        fooSum += i;
-    }
-
-    void bar(long i)
+    static if (is(typeof(mixin(typeof(this).stringof ~ "." ~ signalPrefix ~ ToString!(index)))))
+        mixin SignalImpl!(index + 1, fullName, signalType);
+    else
     {
-        barSum += i;
-    }
-
-    auto a = new A;
-    auto b = new B;
-    auto c = new C;
-    assert(b.scorched.signalId == 0);
-    assert(b.booed.signalId == 1);
-    assert(c.cooked.signalId == 1);
-
-    auto sh = b.signalHandler;
-
-    b.scorched.connect(&foo);
-    assert(sh.connections.length == 1);
-    assert(b.signalId1 == 0);
-    auto scCons = &sh.connections[0];
-
-    assert(scCons.getSlotList!(SlotListId.Func).length == 1);
-    b.scorched.emit(1);
-    assert(fooSum == 1);
-
-    b.scorched.connect(&bar, ConnectionFlags.NoObject);
-    assert(sh.connections.length == 1);
-    assert(scCons.getSlotList!(SlotListId.Strong).length == 1);
-    b.scorched.emit(1);
-    assert (fooSum == 2 && barSum == 1);
+//        pragma(msg, "alias void delegate" ~ getFunc!_Tuple(fullName) ~ " Dg;");
+        mixin("alias void delegate" ~ getFunc!_Tuple(fullName) ~ " Dg;");
+        alias ParameterTypeTuple!(Dg) ArgTypes;
+        enum args = getFunc!_Args(fullName);
+        enum defVals = defaultValues(args);
+        enum defValsLength = defaultValuesLength(defVals);
 
-    b.scorched.connect(&b.baz);
-    assert(scCons.getSlotList!(SlotListId.Weak).length == 1);
-    b.scorched.emit(1);
-    assert (fooSum == 3 && barSum == 2 && b.bazSum == 1);
-
-    b.scorched.disconnect(&bar);
-    assert(scCons.slotCount == 2);
-    b.scorched.disconnect(&b.baz);
-    assert(scCons.slotCount == 1);
-    b.scorched.disconnect(&foo);
-    assert(scCons.slotCount == 0);
-    assert(b.signalId2 == 0);
-
-    fooSum = 0;
-    void connectFoo()
+//        pragma (msg, SignalEmitter!(ArgTypes)(SignalType.NewSignal, getFunc!_Name(fullName), defVals, index));
+        mixin InsertMetaSignal!(fullName, index, defValsLength, ArgTypes);
+//        pragma (msg, ctfe_meta_signal!(ArgTypes)(fullName, index, defValsLength));
+    }
+}
+template MetaMethodImpl(string metaPrefix, int index, string fullName, SignalType signalType)
+{
+    static if (is(typeof(mixin(typeof(this).stringof ~ "." ~ metaPrefix ~ toStringNow!(index)))))
+    {
+        mixin MetaMethodImpl!(metaPrefix, index + 1, fullName, signalType);
+    }
+    else
     {
-        b.scorched.connect(&foo);
-        b.scorched.disconnect(&connectFoo);
+        mixin("alias void delegate" ~ getFunc!_Tuple(fullName) ~ " Dg;");
+        alias ParameterTypeTuple!(Dg) ArgTypes;
+        enum args = getFunc!_Args(fullName);
+        enum defVals = defaultValues(args);
+        enum defValsLength = defaultValuesLength(defVals);
+        
+        static if (metaPrefix == signalPrefix)
+        {
+            // calculating local index of the signal
+            static if (typeof(this).stringof == "QObject")
+                enum localIndex = index;
+            else
+                mixin ("enum localIndex = index - 1 - lastSignalIndex_" ~ (typeof(super)).stringof ~ ";");
+            
+            static if (signalType == SignalType.NewSignal)
+            {
+                pragma (msg, SignalEmitter!(ArgTypes)(SignalType.NewSignal, getFunc!_Name(fullName), defVals, localIndex));
+                mixin (SignalEmitter!(ArgTypes)(SignalType.NewSignal, getFunc!_Name(fullName), defVals, localIndex));
+            }
+        }
+        mixin InsertMetaMethod!(fullName, metaPrefix, index, defValsLength, DefaultArgs.Start, ArgTypes);
+//        pragma (msg, ctfe_meta_signal!(ArgTypes)(fullName, index, defValsLength));
+    }
+}
+template InsertMetaMethod(string fullName, string metaPrefix, int index, int defValsCount, DefaultArgs defArgsInitFlag, ArgTypes...)
+{
+    // this identifies if metamethod is was generated by the presence of default args or not
+    static if(defValsCount > 0)
+    {
+        static if (defArgsInitFlag == DefaultArgs.Start)
+            enum defValsFlag = DefaultArgs.Start;
+        else
+            enum defValsFlag = DefaultArgs.Continue;
     }
+    else
+    {
+        static if (defArgsInitFlag == DefaultArgs.Start)
+            enum defValsFlag = DefaultArgs.None;
+        else
+            enum defValsFlag = DefaultArgs.Continue;
+    }
+    static if(defValsCount >= 0)
+        mixin("public alias TypeTuple!(\"" ~ getFunc!_Name(fullName) ~ "\", index, typeof(this), defValsFlag, ArgTypes) " ~ metaPrefix ~ toStringNow!(index) ~ ";");
+    static if(defValsCount > 0)
+        mixin InsertMetaMethod!(fullName, metaPrefix, index+1, defValsCount-1, DefaultArgs.Continue, ArgTypes[0..$-1]);
+}
 
-    b.scorched.connect(&connectFoo, ConnectionFlags.NoObject);
-    b.scorched.emit(1);
-    assert(scCons.getSlotList!(SlotListId.Func).length == 1);
-    assert(scCons.getSlotList!(SlotListId.Strong).length == 0);
-    assert(!fooSum);
 
-    auto r = new B();
-    b.scorched.connect(&r.baz);
-    assert(scCons.getSlotList!(SlotListId.Weak).length == 1);
-    b.scorched.emit(1);
-    assert(r.bazSum == 1);
-    assert(fooSum == 1);
+string signature_impl(T...)(string name)
+{
+    string res = name ~ "(";
+    foreach(i, _; T)
+    {
+        if(i > 0)
+            res ~= ",";
+        res ~= T[i].stringof;
+    }
+    res ~= ")";
+    return res;
+}
 
-    delete(r);
-    assert(scCons.getSlotList!(SlotListId.Weak).length == 1);
-    b.scorched.emit(1);
-    assert(scCons.getSlotList!(SlotListId.Weak).length == 0);
+template signature(string name, T...)
+{
+    enum signature = signature_impl!(T)(name);
 }
+
+template lastSignalIndex(T)
+{
+    static if (T.stringof == "QObject")
+        enum lastSignalIndex = lastSignalIndexImpl!(T, 0);
+    else
+        mixin ("enum lastSignalIndex = lastSignalIndexImpl!(T, " ~ "T.lastSignalIndex_" ~ (BaseClassesTuple!(T)[0]).stringof ~ ");");
+}
+
+template lastSignalIndexImpl(T, int index)
+{
+    static if (is(typeof(mixin("T." ~ signalPrefix ~ toStringNow!(index)))))
+        enum lastSignalIndexImpl = lastSignalIndexImpl!(T, index + 1);
+    else
+        enum lastSignalIndexImpl = index - 1;
+}
\ No newline at end of file